Added Viewer and
change to App Setting File from Constants
This commit is contained in:
parent
2afec95704
commit
b155863645
47
.groovy
47
.groovy
@ -4,7 +4,6 @@ import groovy.transform.Field
|
||||
|
||||
@Field String _DDrive = 'D:/'
|
||||
@Field String _ExePath = '...'
|
||||
@Field String _AgentStaging = ''
|
||||
@Field String _NGINXFile = '...'
|
||||
@Field String _PortNumber = '...'
|
||||
@Field String _AssemblyName = '...'
|
||||
@ -14,10 +13,10 @@ import groovy.transform.Field
|
||||
@Field String _TargetLocation = '...'
|
||||
@Field String _FirstBeforePlus = '5000'
|
||||
@Field String _GitName = 'OI-Metrology'
|
||||
@Field String _ProjectDirectory = 'Archive'
|
||||
@Field String _MonARessource = 'OI_Metrology'
|
||||
@Field String _WorkingDirectoryName = 'IFXApps'
|
||||
@Field String _DDriveNet = "${_DDrive}${_NetVersion}"
|
||||
@Field String _AgentStaging = 'messa010ec-ecfisysadmin'
|
||||
@Field String _AgentProduction = 'messa010ec-ecfisysadmin'
|
||||
@Field String _CredentialsId = 'Metrology-Username-Password'
|
||||
@Field String _Company = 'Infineon Technologies Americas Corp.'
|
||||
@ -31,6 +30,7 @@ pipeline {
|
||||
string(name: 'MONA_SUFFIX', defaultValue: env.JENKINS_ENVIRONMENT == 'Development' ? '_IFX' : '_EC', description: 'MonA Suffix')
|
||||
string(name: 'GIT_SERVER', defaultValue: env.JENKINS_ENVIRONMENT == 'Development' ? 'mestsa003.infineon.com' : 'mestsa07ec.ec.local', description: 'git server')
|
||||
string(name: 'DEFAULT_FILE_SERVER', defaultValue: env.JENKINS_ENVIRONMENT == 'Development' ? 'messv02ecc1_ec_local' : 'messv02ecc1.ec.local', description: 'Default file server...')
|
||||
string(name: 'PROJECT_DIRECTORY', defaultValue: 'Archive', description: 'Archive|Viewer')
|
||||
}
|
||||
stages {
|
||||
stage('Git') {
|
||||
@ -43,10 +43,10 @@ pipeline {
|
||||
stage('Setup') {
|
||||
steps {
|
||||
script {
|
||||
_AssemblyName = "${env.JOB_NAME}"
|
||||
_AssemblyName = "${env.JOB_NAME}-${env.PROJECT_DIRECTORY}"
|
||||
_GitCommitSeven = '1234567'
|
||||
// _GitCommitSeven = env.GIT_COMMIT.substring(0, 7)
|
||||
dir(_ProjectDirectory) {
|
||||
dir(env.PROJECT_DIRECTORY) {
|
||||
def files = findFiles(glob: '*.csproj')
|
||||
if (files.length != 1) {
|
||||
error("Build failed because couldn't find a *.csproj file")
|
||||
@ -85,7 +85,7 @@ pipeline {
|
||||
else {
|
||||
_PortNumber = (segments[2].toInteger() + 2).toString()
|
||||
}
|
||||
_ExePath = "${_DDriveNet}/${_GitCommitSeven}-${env.BUILD_NUMBER}-${_PortNumber}-${env.JOB_NAME}/${_AssemblyName}.exe"
|
||||
_ExePath = "${_DDriveNet}/${_GitCommitSeven}-${env.BUILD_NUMBER}-${_PortNumber}-${env.JOB_NAME}-${env.PROJECT_DIRECTORY}/${_AssemblyName}.exe"
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -111,6 +111,7 @@ pipeline {
|
||||
echo "JENKINS_ENVIRONMENT ${env.JENKINS_ENVIRONMENT}" // 11
|
||||
echo "JENKINS_URL ${env.JENKINS_URL}" // http://localhost:8080/
|
||||
echo "JOB_NAME ${env.JOB_NAME}" // ...
|
||||
echo "PROJECT_DIRECTORY ${env.PROJECT_DIRECTORY}" // ...
|
||||
echo "WORKSPACE ${env.WORKSPACE}" // D:\.jenkins\_\...
|
||||
}
|
||||
}
|
||||
@ -122,7 +123,7 @@ pipeline {
|
||||
stage('Safe storage of app secrets') {
|
||||
steps {
|
||||
withCredentials([usernamePassword(credentialsId: _CredentialsId, passwordVariable: 'password', usernameVariable: 'username')]) {
|
||||
dir(_ProjectDirectory) {
|
||||
dir(env.PROJECT_DIRECTORY) {
|
||||
bat(returnStatus: true, script: '"' + _ProgramFilesDotnet + '" ' +
|
||||
'user-secrets init')
|
||||
bat(returnStatus: true, script: '"' + _ProgramFilesDotnet + '" ' +
|
||||
@ -140,7 +141,7 @@ pipeline {
|
||||
bat(returnStatus: true, script: '"' + _ProgramFilesDotnet + '" ' +
|
||||
'user-secrets set "WorkingDirectoryName" "' + _WorkingDirectoryName + '"')
|
||||
bat(returnStatus: true, script: '"' + _ProgramFilesDotnet + '" ' +
|
||||
'user-secrets set "MonARessource" "' + _MonARessource + env.MONA_SUFFIX + '"')
|
||||
'user-secrets set "MonARessource" "' + _MonARessource + '_' + env.PROJECT_DIRECTORY + env.MONA_SUFFIX + '"')
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -148,7 +149,7 @@ pipeline {
|
||||
// stage('Core Build (packagemanagement.eu.infineon.com)') {
|
||||
// steps {
|
||||
// echo "Build number is ${currentBuild.number}"
|
||||
// dir(_ProjectDirectory) {
|
||||
// dir(env.PROJECT_DIRECTORY) {
|
||||
// bat(returnStatus: true, script: '"' + _ProgramFilesDotnet + '" ' +
|
||||
// 'build --runtime win-x64 --self-contained --verbosity quiet --source ' +
|
||||
// 'https://packagemanagement.eu.infineon.com:4430/api/v2/')
|
||||
@ -158,7 +159,7 @@ pipeline {
|
||||
stage('Core Build') {
|
||||
steps {
|
||||
echo "Build number is ${currentBuild.number}"
|
||||
dir(_ProjectDirectory) {
|
||||
dir(env.PROJECT_DIRECTORY) {
|
||||
bat(returnStatus: true, script: '"' + _ProgramFilesDotnet + '" ' +
|
||||
'build --runtime win-x64 --self-contained --verbosity quiet')
|
||||
}
|
||||
@ -166,7 +167,7 @@ pipeline {
|
||||
}
|
||||
stage('Commit Id') {
|
||||
steps {
|
||||
dir(_ProjectDirectory) {
|
||||
dir(env.PROJECT_DIRECTORY) {
|
||||
writeFile(file: 'bin/Debug/' + _NetVersion + "/win-x64/${env.GIT_COMMIT}-${env.BUILD_NUMBER}.txt", text: "${env.GIT_URL}")
|
||||
}
|
||||
}
|
||||
@ -176,7 +177,7 @@ pipeline {
|
||||
// timeout(time: 10, unit: 'MINUTES')
|
||||
// }
|
||||
// steps {
|
||||
// dir(_ProjectDirectory) {
|
||||
// dir(env.PROJECT_DIRECTORY) {
|
||||
// bat('dotnet --info')
|
||||
// }
|
||||
// }
|
||||
@ -188,32 +189,30 @@ pipeline {
|
||||
// }
|
||||
stage('Package') {
|
||||
steps {
|
||||
dir(_ProjectDirectory) {
|
||||
fileOperations([fileZipOperation(folderPath: 'bin/Debug/' + _NetVersion + '/win-x64', outputFolderPath: "${_DDriveNet}/${_GitCommitSeven}-${env.BUILD_NUMBER}-${_PortNumber}-${env.JOB_NAME}-Debug")])
|
||||
fileOperations([fileCopyOperation(excludes: '', flattenFiles: true, includes: "${_AssemblyName}*", renameFiles: false, sourceCaptureExpression: '', targetLocation: "${_DDriveNet}/${_GitCommitSeven}-${env.BUILD_NUMBER}-${_PortNumber}-${env.JOB_NAME}-Debug", targetNameExpression: '')])
|
||||
dir(env.PROJECT_DIRECTORY) {
|
||||
fileOperations([fileZipOperation(folderPath: 'bin/Debug/' + _NetVersion + '/win-x64', outputFolderPath: "${_DDriveNet}/${_GitCommitSeven}-${env.BUILD_NUMBER}-${_PortNumber}-${env.JOB_NAME}-${env.PROJECT_DIRECTORY}-Debug")])
|
||||
fileOperations([fileCopyOperation(excludes: '', flattenFiles: true, includes: "${_AssemblyName}*", renameFiles: false, sourceCaptureExpression: '', targetLocation: "${_DDriveNet}/${_GitCommitSeven}-${env.BUILD_NUMBER}-${_PortNumber}-${env.JOB_NAME}-${env.PROJECT_DIRECTORY}-Debug", targetNameExpression: '')])
|
||||
}
|
||||
}
|
||||
}
|
||||
stage('Publish') {
|
||||
steps {
|
||||
dir(_ProjectDirectory) {
|
||||
bat(returnStatus: true, script: '"' + _ProgramFilesDotnet + '" ' +
|
||||
'remove reference "../Client/' + env.JOB_NAME + '.Client.csproj"')
|
||||
dir(env.PROJECT_DIRECTORY) {
|
||||
bat(returnStatus: true, script: '"' + _ProgramFilesDotnet + '" ' +
|
||||
'publish --configuration Release --runtime win-x64 --verbosity quiet ' +
|
||||
"--self-contained true --p:Version=6.0.202-${_GitCommitSeven}-${env.BUILD_NUMBER} -o " +
|
||||
'"' + "${_DDriveNet}/${_GitCommitSeven}-${env.BUILD_NUMBER}-${_PortNumber}-${env.JOB_NAME}" + '"')
|
||||
'"' + "${_DDriveNet}/${_GitCommitSeven}-${env.BUILD_NUMBER}-${_PortNumber}-${env.JOB_NAME}-${env.PROJECT_DIRECTORY}" + '"')
|
||||
}
|
||||
}
|
||||
}
|
||||
stage('Service') {
|
||||
steps {
|
||||
withCredentials([usernamePassword(credentialsId: _CredentialsId, passwordVariable: 'password', usernameVariable: 'username')]) {
|
||||
bat(returnStatus: true, script: 'sc create "' + "${env.JOB_NAME}-${_PortNumber}" + '" ' +
|
||||
'start= delayed-auto DisplayName="' + "${env.JOB_NAME}-${_PortNumber}" + '" ' +
|
||||
bat(returnStatus: true, script: 'sc create "' + "${env.JOB_NAME}-${env.PROJECT_DIRECTORY}-${_PortNumber}" + '" ' +
|
||||
'start= delayed-auto DisplayName="' + "${env.JOB_NAME}-${env.PROJECT_DIRECTORY}-${_PortNumber}" + '" ' +
|
||||
'binPath= "' + _ExePath + '" ' +
|
||||
'obj= "' + "${env.USERDOMAIN}\\${username}" + '" password= "' + password + '"')
|
||||
bat(returnStatus: true, script: 'sc start "' + "${env.JOB_NAME}-${_PortNumber}" + '"')
|
||||
bat(returnStatus: true, script: 'sc start "' + "${env.JOB_NAME}-${env.PROJECT_DIRECTORY}-${_PortNumber}" + '"')
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -244,7 +243,7 @@ pipeline {
|
||||
// }
|
||||
// stage('Copy Files to: file-share') {
|
||||
// steps {
|
||||
// dir(_ProjectDirectory + '/bin/Debug/' + _NetVersion + '/win-x64') {
|
||||
// dir(env.PROJECT_DIRECTORY + '/bin/Debug/' + _NetVersion + '/win-x64') {
|
||||
// fileOperations([fileCopyOperation(excludes: '', flattenFiles: true, includes: "${_AssemblyName}*.txt", renameFiles: false, sourceCaptureExpression: '', targetLocation: _TargetLocation, targetNameExpression: '')])
|
||||
// fileOperations([fileCopyOperation(excludes: '', flattenFiles: true, includes: "${_AssemblyName}*.dll", renameFiles: false, sourceCaptureExpression: '', targetLocation: _TargetLocation, targetNameExpression: '')])
|
||||
// fileOperations([fileCopyOperation(excludes: '', flattenFiles: true, includes: "${_AssemblyName}*.exe", renameFiles: false, sourceCaptureExpression: '', targetLocation: _TargetLocation, targetNameExpression: '')])
|
||||
@ -255,10 +254,10 @@ pipeline {
|
||||
}
|
||||
post {
|
||||
always {
|
||||
dir(_ProjectDirectory + '/bin') {
|
||||
dir(env.PROJECT_DIRECTORY + '/bin') {
|
||||
deleteDir()
|
||||
}
|
||||
dir(_ProjectDirectory + '/obj') {
|
||||
dir(env.PROJECT_DIRECTORY + '/obj') {
|
||||
deleteDir()
|
||||
}
|
||||
// cleanWs()
|
||||
|
3
Archive/.vscode/launch.json
vendored
3
Archive/.vscode/launch.json
vendored
@ -29,7 +29,8 @@
|
||||
{
|
||||
"name": ".NET Core Attach",
|
||||
"type": "coreclr",
|
||||
"request": "attach"
|
||||
"request": "attach",
|
||||
"processName": "Archive"
|
||||
}
|
||||
]
|
||||
}
|
@ -8,8 +8,8 @@ using System.IO;
|
||||
namespace OI.Metrology.Archive.ApiControllers;
|
||||
public class AttachmentsController : Controller
|
||||
{
|
||||
protected IMetrologyRepo _Repo;
|
||||
protected IAttachmentsService _AttachmentsService;
|
||||
private readonly IMetrologyRepo _Repo;
|
||||
private readonly IAttachmentsService _AttachmentsService;
|
||||
|
||||
public AttachmentsController(IMetrologyRepo repo, IAttachmentsService attachmentsService)
|
||||
{
|
||||
|
@ -9,7 +9,7 @@ using System.Text.Json;
|
||||
|
||||
public class AwaitingDispoController : Controller
|
||||
{
|
||||
protected IMetrologyRepo _Repo;
|
||||
private readonly IMetrologyRepo _Repo;
|
||||
|
||||
public AwaitingDispoController(IMetrologyRepo repo) => _Repo = repo;
|
||||
|
||||
|
@ -1,8 +1,8 @@
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using OI.Metrology.Archive.Models;
|
||||
using OI.Metrology.Shared.DataModels;
|
||||
using OI.Metrology.Shared.Repositories;
|
||||
using OI.Metrology.Shared.Services;
|
||||
@ -15,20 +15,19 @@ namespace OI.Metrology.Archive.ApiContollers;
|
||||
[ApiController]
|
||||
public class InboundController : ControllerBase
|
||||
{
|
||||
private IConfiguration Config { get; }
|
||||
private ILogger Logger { get; }
|
||||
private readonly ILogger _Logger;
|
||||
private readonly IMetrologyRepo _Repo;
|
||||
private readonly AppSettings _AppSettings;
|
||||
private readonly IAttachmentsService _AttachmentService;
|
||||
private readonly IInboundDataService _InboundDataService;
|
||||
|
||||
protected IMetrologyRepo _Repo;
|
||||
protected IAttachmentsService _AttachmentService;
|
||||
protected IInboundDataService _InboundDataService;
|
||||
|
||||
public InboundController(IConfiguration config, ILogger<InboundController> logger, IMetrologyRepo repo, IInboundDataService inboundDataService, IAttachmentsService attachmentService)
|
||||
public InboundController(AppSettings appSettings, ILogger<InboundController> logger, IMetrologyRepo repo, IInboundDataService inboundDataService, IAttachmentsService attachmentService)
|
||||
{
|
||||
Config = config;
|
||||
Logger = logger;
|
||||
_Repo = repo;
|
||||
_InboundDataService = inboundDataService;
|
||||
_Logger = logger;
|
||||
_AppSettings = appSettings;
|
||||
_AttachmentService = attachmentService;
|
||||
_InboundDataService = inboundDataService;
|
||||
}
|
||||
|
||||
// this class represents the API response back to the client
|
||||
@ -57,7 +56,7 @@ public class InboundController : ControllerBase
|
||||
|
||||
if (!IsIPAddressAllowed())
|
||||
{
|
||||
Logger.LogInformation($"Rejected remote IP: {HttpContext.Connection.RemoteIpAddress}");
|
||||
_Logger.LogInformation($"Rejected remote IP: {HttpContext.Connection.RemoteIpAddress}");
|
||||
r.Errors.Add("Remote IP is not on allowed list");
|
||||
return Unauthorized(r);
|
||||
}
|
||||
@ -115,7 +114,7 @@ public class InboundController : ControllerBase
|
||||
{
|
||||
if (!IsIPAddressAllowed())
|
||||
{
|
||||
Logger.LogInformation($"Rejected remote IP: {HttpContext.Connection.RemoteIpAddress}");
|
||||
_Logger.LogInformation($"Rejected remote IP: {HttpContext.Connection.RemoteIpAddress}");
|
||||
return Unauthorized("Remote IP is not on allowed list");
|
||||
}
|
||||
|
||||
@ -145,14 +144,13 @@ public class InboundController : ControllerBase
|
||||
|
||||
protected bool IsIPAddressAllowed()
|
||||
{
|
||||
string allowedList = Config[Constants.InboundApiAllowedIPList];
|
||||
if (string.IsNullOrWhiteSpace(allowedList))
|
||||
if (string.IsNullOrWhiteSpace(_AppSettings.InboundApiAllowedIPList))
|
||||
return true;
|
||||
|
||||
System.Net.IPAddress remoteIP = HttpContext.Connection.RemoteIpAddress;
|
||||
byte[] remoteIPBytes = remoteIP.GetAddressBytes();
|
||||
|
||||
string[] allowedIPs = allowedList.Split(';');
|
||||
string[] allowedIPs = _AppSettings.InboundApiAllowedIPList.Split(';');
|
||||
foreach (string ip in allowedIPs)
|
||||
{
|
||||
System.Net.IPAddress parsedIP;
|
||||
|
@ -1,5 +1,4 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.IO;
|
||||
@ -7,6 +6,7 @@ using System.Linq;
|
||||
|
||||
namespace OI.Metrology.Archive.ApiContollers;
|
||||
|
||||
using OI.Metrology.Archive.Models;
|
||||
using OI.Metrology.Shared.DataModels;
|
||||
using OI.Metrology.Shared.Repositories;
|
||||
using OI.Metrology.Shared.Services;
|
||||
@ -21,15 +21,14 @@ public class ToolTypesController : Controller
|
||||
// it is named after the /api/tooltypes prefix
|
||||
// the URL pattern is RESTful and the tool type is the root of every request
|
||||
|
||||
private IConfiguration Config { get; }
|
||||
private readonly IMetrologyRepo _Repo;
|
||||
private readonly AppSettings _AppSettings;
|
||||
private readonly IAttachmentsService _AttachmentsService;
|
||||
|
||||
protected IMetrologyRepo _Repo;
|
||||
protected IAttachmentsService _AttachmentsService;
|
||||
|
||||
public ToolTypesController(IConfiguration config, IMetrologyRepo repo, IAttachmentsService attachmentsService)
|
||||
public ToolTypesController(AppSettings appSettings, IMetrologyRepo repo, IAttachmentsService attachmentsService)
|
||||
{
|
||||
Config = config;
|
||||
_Repo = repo;
|
||||
_AppSettings = appSettings;
|
||||
_AttachmentsService = attachmentsService;
|
||||
}
|
||||
|
||||
@ -67,7 +66,7 @@ public class ToolTypesController : Controller
|
||||
};
|
||||
return Json(r, new JsonSerializerOptions { PropertyNamingPolicy = null, WriteIndented = true });
|
||||
}
|
||||
//Just Changed here
|
||||
// Just Changed here
|
||||
// Gets headers, request/response format is to allow paging with igniteUI
|
||||
// The headerid parameter is used for navigating directly to a header, when the button is clicked in Awaiting Dispo
|
||||
[HttpGet("/api/tooltypes/{id}/headers")]
|
||||
@ -77,11 +76,11 @@ public class ToolTypesController : Controller
|
||||
[FromQuery] DateTime? dateend,
|
||||
[FromQuery] int? page,
|
||||
[FromQuery] int? pagesize,
|
||||
[FromQuery] long? headerid, bool isSharePoint)
|
||||
[FromQuery] long? headerid)
|
||||
{
|
||||
long totalRecs;
|
||||
|
||||
System.Data.DataTable dt = _Repo.GetHeaders(id, datebegin, dateend, page, pagesize, headerid, out totalRecs, isSharePoint);
|
||||
System.Data.DataTable dt = _Repo.GetHeaders(id, datebegin, dateend, page, pagesize, headerid, out totalRecs);
|
||||
|
||||
var r = new
|
||||
{
|
||||
@ -98,11 +97,11 @@ public class ToolTypesController : Controller
|
||||
public IActionResult GetHeaderTitles(
|
||||
int id,
|
||||
[FromQuery] int? page,
|
||||
[FromQuery] int? pagesize, bool isArchive)
|
||||
[FromQuery] int? pagesize)
|
||||
{
|
||||
long totalRecs;
|
||||
|
||||
IEnumerable<HeaderCommon> dt = _Repo.GetHeaderTitles(id, page, pagesize, out totalRecs, isArchive);
|
||||
IEnumerable<HeaderCommon> dt = _Repo.GetHeaderTitles(id, page, pagesize, out totalRecs);
|
||||
|
||||
var r = new
|
||||
{
|
||||
@ -118,11 +117,11 @@ public class ToolTypesController : Controller
|
||||
[HttpGet("/api/tooltypes/{id}/headers/{headerid}/fields")]
|
||||
public IActionResult GetHeaderFields(
|
||||
int id,
|
||||
long headerid, bool isArchive)
|
||||
long headerid)
|
||||
{
|
||||
var r = new
|
||||
{
|
||||
Results = _Repo.GetHeaderFields(id, headerid, isArchive).Select(x => new { Column = x.Key, x.Value }).ToList()
|
||||
Results = _Repo.GetHeaderFields(id, headerid).Select(x => new { Column = x.Key, x.Value }).ToList()
|
||||
};
|
||||
string json = JsonConvert.SerializeObject(r);
|
||||
|
||||
@ -148,12 +147,12 @@ public class ToolTypesController : Controller
|
||||
[HttpGet("/api/tooltypes/{id}/headers/{headerid}/data")]
|
||||
public IActionResult GetData(
|
||||
int id,
|
||||
long headerid, bool isSharePoint)
|
||||
long headerid)
|
||||
{
|
||||
|
||||
var r = new
|
||||
{
|
||||
Results = _Repo.GetData(id, headerid, isSharePoint)
|
||||
Results = _Repo.GetData(id, headerid)
|
||||
};
|
||||
string json = JsonConvert.SerializeObject(r);
|
||||
|
||||
@ -166,7 +165,7 @@ public class ToolTypesController : Controller
|
||||
int toolTypeId,
|
||||
string tabletype,
|
||||
string attachmentId,
|
||||
string filename, bool isArchive)
|
||||
string filename)
|
||||
{
|
||||
|
||||
ToolType tt = _Repo.GetToolTypeByID(toolTypeId);
|
||||
@ -177,8 +176,6 @@ public class ToolTypesController : Controller
|
||||
if (!Guid.TryParse(attachmentId, out attachmentIdParsed))
|
||||
return Content("Invalid attachment id");
|
||||
|
||||
//try
|
||||
// {
|
||||
// figure out what content type to use. this is very simple because there are only two types being used
|
||||
string contenttype = "application/pdf";
|
||||
if (filename.ToLower().TrimEnd().EndsWith(".txt"))
|
||||
@ -186,18 +183,7 @@ public class ToolTypesController : Controller
|
||||
|
||||
// Get attachment stream and feed it to the client
|
||||
Stream fs = _AttachmentsService.GetAttachmentStreamByAttachmentId(tt, header, attachmentIdParsed, filename);
|
||||
/*if (isArchive)
|
||||
{
|
||||
fs = attachmentsService.GetAttachmentStreamByAttachmentIdArchive(tt, header, attachmentIdParsed, filename);
|
||||
//fs = attachmentsService.GetAttachmentStreamByAttachmentId
|
||||
}*/
|
||||
|
||||
return File(fs, contenttype);
|
||||
//}
|
||||
/*catch (Exception ex)
|
||||
{
|
||||
return Content(ex.Message);
|
||||
}*/
|
||||
}
|
||||
|
||||
// This endpoint triggers writing of the OI Export file
|
||||
@ -247,13 +233,9 @@ public class ToolTypesController : Controller
|
||||
// The output file will only have one line, the header columns are output first
|
||||
// Then each detail rows has it's columns appended
|
||||
// H1, H2, H3, D1.1, D1.2, D1.3, D2.1, D2.2, D2.3, etc
|
||||
|
||||
// Get the configured export path
|
||||
string exportRootPath = Config[Constants.OIExportPathKey];
|
||||
|
||||
// Write the file
|
||||
System.IO.File.WriteAllText(
|
||||
Path.Join(exportRootPath, filename),
|
||||
Path.Join(_AppSettings.OIExportPath, filename),
|
||||
sb.ToString());
|
||||
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using OI.Metrology.Archive.Models;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
@ -12,13 +12,13 @@ namespace OI.Metrology.Archive;
|
||||
// You may need to install the Microsoft.AspNetCore.Http.Abstractions package into your project
|
||||
public class ApiLoggingMiddleware
|
||||
{
|
||||
private IConfiguration Config { get; }
|
||||
private readonly RequestDelegate _Next;
|
||||
private readonly AppSettings _AppSettings;
|
||||
|
||||
public ApiLoggingMiddleware(RequestDelegate next, IConfiguration config)
|
||||
public ApiLoggingMiddleware(RequestDelegate next, AppSettings appSettings)
|
||||
{
|
||||
Config = config;
|
||||
_Next = next;
|
||||
_AppSettings = appSettings;
|
||||
}
|
||||
|
||||
// this is the method called in ASP.NET Core middleware to handle an HTTP request
|
||||
@ -29,25 +29,22 @@ public class ApiLoggingMiddleware
|
||||
try
|
||||
{
|
||||
bool doLogging = false;
|
||||
string pathsToLog = Config[Constants.ApiLoggingPathPrefixes];
|
||||
string contentTypesToLog = Config[Constants.ApiLoggingContentTypes];
|
||||
|
||||
// check to see if this is a request path that is enabled for logging
|
||||
if (!string.IsNullOrWhiteSpace(pathsToLog))
|
||||
if (!string.IsNullOrWhiteSpace(_AppSettings.ApiLoggingPathPrefixes))
|
||||
{
|
||||
// check if the request path begins with any part of pathsToLog
|
||||
if (pathsToLog.Split(';').Any(p => httpContext.Request.Path.StartsWithSegments(new PathString(p))))
|
||||
if (_AppSettings.ApiLoggingPathPrefixes.Split(';').Any(p => httpContext.Request.Path.StartsWithSegments(new PathString(p))))
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(contentTypesToLog))
|
||||
{
|
||||
// if there are content type filters configured, only log is the request begins with one of them
|
||||
doLogging = contentTypesToLog.Split(';').Any(ct => httpContext.Request.ContentType.StartsWith(ct));
|
||||
}
|
||||
else
|
||||
if (string.IsNullOrWhiteSpace(_AppSettings.ApiLoggingContentTypes))
|
||||
{
|
||||
// if no content type filter is defined, log all content types
|
||||
doLogging = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// if there are content type filters configured, only log is the request begins with one of them
|
||||
doLogging = _AppSettings.ApiLoggingContentTypes.Split(';').Any(ct => httpContext.Request.ContentType.StartsWith(ct));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -107,15 +104,14 @@ public class ApiLoggingMiddleware
|
||||
{
|
||||
int threadId = Environment.CurrentManagedThreadId;
|
||||
|
||||
string logPath = Config[Constants.ApiLogPath];
|
||||
string fileName = $"ApiLog{requestTime:yyyyMMdd_hhmmssttt}_{threadId}.txt";
|
||||
|
||||
HttpContext context = request.HttpContext;
|
||||
|
||||
if (!Directory.Exists(logPath))
|
||||
_ = Directory.CreateDirectory(logPath);
|
||||
if (!Directory.Exists(_AppSettings.ApiLogPath))
|
||||
_ = Directory.CreateDirectory(_AppSettings.ApiLogPath);
|
||||
|
||||
using StreamWriter sw = new(Path.Join(logPath, fileName), true);
|
||||
using StreamWriter sw = new(Path.Join(_AppSettings.ApiLogPath, fileName), true);
|
||||
sw.WriteLine($"Request at {requestTime:yyyy/MM/dd hh:mm:ss.ttt} from {context.Connection.RemoteIpAddress}");
|
||||
sw.WriteLine($"{request.Method} {request.Path} {request.QueryString}");
|
||||
sw.WriteLine("Request body:");
|
||||
|
@ -34,7 +34,14 @@
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="6.0.1" />
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting.WindowsServices" Version="6.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting" Version="6.0.1" />
|
||||
<PackageReference Include="Microsoft.Web.LibraryManager.Build" Version="2.1.175" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Serilog.AspNetCore" Version="5.0.0" />
|
||||
<PackageReference Include="Serilog.AspNetCore.Ingestion" Version="1.0.0-dev-00021" />
|
||||
<PackageReference Include="Serilog.Settings.Configuration" Version="3.3.0" />
|
||||
<PackageReference Include="Serilog.Sinks.Console" Version="4.0.1" />
|
||||
<PackageReference Include="Serilog.Sinks.File" Version="5.0.0" />
|
||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.4.0" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="System.Data.SqlClient" Version="4.8.3" />
|
||||
|
@ -1,13 +0,0 @@
|
||||
namespace OI.Metrology.Archive;
|
||||
|
||||
public static class Constants
|
||||
{
|
||||
public const string ConnStringName = "SQL";
|
||||
public const string ConnStringName2 = "SQL2";
|
||||
public const string AttachmentPathKey = "AttachmentPath";
|
||||
public const string OIExportPathKey = "OIExportPath";
|
||||
public const string InboundApiAllowedIPList = "InboundApiAllowedIPList";
|
||||
public const string ApiLoggingPathPrefixes = "ApiLoggingPathPrefixes";
|
||||
public const string ApiLoggingContentTypes = "ApiLoggingContentTypes";
|
||||
public const string ApiLogPath = "ApiLogPath";
|
||||
}
|
@ -8,9 +8,9 @@ namespace OI.Metrology.Archive.Controllers;
|
||||
[Route("/error")]
|
||||
public class ErrorHandlerController : Controller
|
||||
{
|
||||
private ILogger Logger { get; }
|
||||
private readonly ILogger _Logger;
|
||||
|
||||
public ErrorHandlerController(ILogger<ErrorHandlerController> logger) => Logger = logger;
|
||||
public ErrorHandlerController(ILogger<ErrorHandlerController> logger) => _Logger = logger;
|
||||
|
||||
public IActionResult Index()
|
||||
{
|
||||
@ -21,7 +21,7 @@ public class ErrorHandlerController : Controller
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger.LogError("Unhandled exception: " + error.Error.ToString());
|
||||
_Logger.LogError("Unhandled exception: " + error.Error.ToString());
|
||||
dynamic r = new
|
||||
{
|
||||
Message = error.Error == null ? "Error" : error.Error.Message
|
||||
|
@ -1,5 +1,7 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.Filters;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using OI.Metrology.Archive.Models;
|
||||
using OI.Metrology.Shared.DataModels;
|
||||
using OI.Metrology.Shared.Repositories;
|
||||
using OI.Metrology.Shared.ViewModels;
|
||||
@ -12,35 +14,33 @@ namespace OI.Metrology.Archive.Controllers;
|
||||
|
||||
public class ExportController : Controller
|
||||
{
|
||||
private ILogger Logger { get; }
|
||||
private readonly ILogger _Logger;
|
||||
private readonly bool _IsTestDatabase;
|
||||
private readonly IMetrologyRepo _Repo;
|
||||
|
||||
protected IMetrologyRepo _Repo;
|
||||
|
||||
public ExportController(ILogger<ExportController> logger, IMetrologyRepo repo)
|
||||
public ExportController(AppSettings appSettings, ILogger<ExportController> logger, IMetrologyRepo repo)
|
||||
{
|
||||
Logger = logger;
|
||||
_Repo = repo;
|
||||
_Logger = logger;
|
||||
_IsTestDatabase = appSettings.ConnectionString.Contains("test", StringComparison.InvariantCultureIgnoreCase);
|
||||
}
|
||||
|
||||
protected static void LoadToolTypes(Export m, IEnumerable<ToolType> toolTypes)
|
||||
public override void OnActionExecuted(ActionExecutedContext context)
|
||||
{
|
||||
m.ToolTypes = toolTypes
|
||||
.Where(tt => tt.ExportSPName != null)
|
||||
.Select(tt => new Shared.Models.SelectListItem(tt.ToolTypeName, tt.ID.ToString())).ToList();
|
||||
base.OnActionExecuted(context);
|
||||
ViewBag.IsTestDatabase = _IsTestDatabase;
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
[Route("/Export")]
|
||||
public ActionResult Index()
|
||||
{
|
||||
Export model = new();
|
||||
|
||||
LoadToolTypes(model, _Repo.GetToolTypes());
|
||||
|
||||
model.ToolType = "";
|
||||
model.StartTime = DateTime.Now.AddMonths(-1);
|
||||
model.EndTime = DateTime.Now;
|
||||
|
||||
Export model = new()
|
||||
{
|
||||
ToolType = "",
|
||||
StartTime = DateTime.Now.AddMonths(-1),
|
||||
EndTime = DateTime.Now
|
||||
};
|
||||
return View(model);
|
||||
}
|
||||
|
||||
@ -48,19 +48,20 @@ public class ExportController : Controller
|
||||
[Route("/ExportData")]
|
||||
public ActionResult ExportData(Export model)
|
||||
{
|
||||
IEnumerable<ToolType> toolTypes = _Repo.GetToolTypes();
|
||||
|
||||
// is tooltype valid
|
||||
ToolType toolType = toolTypes.Where(tt => tt.ID.ToString() == model.ToolType).SingleOrDefault();
|
||||
if (toolType == null)
|
||||
ModelState.AddModelError("ToolType", "Invalid selection");
|
||||
else if (string.IsNullOrWhiteSpace(toolType.ExportSPName))
|
||||
ModelState.AddModelError("ToolType", "Tool type is not exportable");
|
||||
|
||||
// is enddate after startdate
|
||||
if (model.StartTime > model.EndTime)
|
||||
ModelState.AddModelError("EndTime", "End time must be after start time");
|
||||
|
||||
ToolType toolType = null;
|
||||
if (string.IsNullOrEmpty(model.ToolType))
|
||||
ModelState.AddModelError("Exception", "Invalid selection");
|
||||
else
|
||||
{
|
||||
if (model.StartTime > model.EndTime)
|
||||
ModelState.AddModelError("EndTime", "End time must be after start time");
|
||||
IEnumerable<ToolType> toolTypes = _Repo.GetToolTypes();
|
||||
toolType = toolTypes.Where(tt => tt.ID.ToString() == model.ToolType).SingleOrDefault();
|
||||
if (toolType is null)
|
||||
ModelState.AddModelError("ToolType", "Invalid selection");
|
||||
else if (string.IsNullOrWhiteSpace(toolType.ExportSPName))
|
||||
ModelState.AddModelError("ToolType", "Tool type is not exportable");
|
||||
}
|
||||
if (ModelState.IsValid)
|
||||
{
|
||||
try
|
||||
@ -72,19 +73,16 @@ public class ExportController : Controller
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ModelState.AddModelError("", "Error exporting data");
|
||||
ModelState.AddModelError("", ex.Message);
|
||||
ModelState.AddModelError("Exception", "Error exporting data");
|
||||
ModelState.AddModelError("Exception", ex.Message);
|
||||
string errorMessage = $"Error exporting: {ex}";
|
||||
Logger.LogError(message: errorMessage);
|
||||
_Logger.LogError(message: errorMessage);
|
||||
}
|
||||
}
|
||||
|
||||
LoadToolTypes(model, toolTypes);
|
||||
|
||||
return View("Index", model);
|
||||
}
|
||||
|
||||
protected ActionResult DoCSVExport(String toolTypeName, string spName, DateTime startTime, DateTime endTime)
|
||||
protected ActionResult DoCSVExport(string toolTypeName, string spName, DateTime startTime, DateTime endTime)
|
||||
{
|
||||
string fileName = string.Format("Export_{0}_{1:yyyyMMddHHmm}_to_{2:yyyyMMddHHmm}.csv", toolTypeName, startTime, endTime);
|
||||
StringBuilder sb = new();
|
||||
|
@ -1,21 +1,32 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.Filters;
|
||||
using OI.Metrology.Archive.Models;
|
||||
using OI.Metrology.Shared.Repositories;
|
||||
using OI.Metrology.Shared.ViewModels;
|
||||
using System;
|
||||
|
||||
namespace OI.Metrology.Archive.Controllers;
|
||||
|
||||
//[Authorize]
|
||||
public class PagesController : Controller
|
||||
{
|
||||
protected IMetrologyRepo _Repo;
|
||||
private readonly IMetrologyRepo _Repo;
|
||||
private readonly bool _IsTestDatabase;
|
||||
|
||||
public PagesController(IMetrologyRepo repo) => _Repo = repo;
|
||||
public PagesController(AppSettings appSettings, IMetrologyRepo repo)
|
||||
{
|
||||
_Repo = repo;
|
||||
_IsTestDatabase = appSettings.ConnectionString.Contains("test", StringComparison.InvariantCultureIgnoreCase);
|
||||
}
|
||||
|
||||
public override void OnActionExecuted(ActionExecutedContext context)
|
||||
{
|
||||
base.OnActionExecuted(context);
|
||||
ViewBag.IsTestDatabase = _IsTestDatabase;
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
[Route("/")]
|
||||
public IActionResult Index() =>
|
||||
//return View("Home");
|
||||
View("RunHeaders");
|
||||
|
||||
[HttpGet]
|
||||
|
60
Archive/Models/AppSettings.cs
Normal file
60
Archive/Models/AppSettings.cs
Normal file
@ -0,0 +1,60 @@
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace OI.Metrology.Archive.Models;
|
||||
|
||||
public class AppSettings
|
||||
{
|
||||
|
||||
protected string _ApiLoggingContentTypes;
|
||||
protected string _ApiLoggingPathPrefixes;
|
||||
protected string _ApiLogPath;
|
||||
protected string _AttachmentPath;
|
||||
protected string _BuildNumber;
|
||||
protected string _Company;
|
||||
protected string _ConnectionString;
|
||||
protected string _GitCommitSeven;
|
||||
protected string _InboundApiAllowedIPList;
|
||||
protected string _MonARessource;
|
||||
protected string _OIExportPath;
|
||||
protected string _URLs;
|
||||
protected string _WorkingDirectoryName;
|
||||
public string ApiLoggingContentTypes => _ApiLoggingContentTypes;
|
||||
public string ApiLoggingPathPrefixes => _ApiLoggingPathPrefixes;
|
||||
public string ApiLogPath => _ApiLogPath;
|
||||
public string AttachmentPath => _AttachmentPath;
|
||||
public string BuildNumber => _BuildNumber;
|
||||
public string Company => _Company;
|
||||
public string ConnectionString => _ConnectionString;
|
||||
public string GitCommitSeven => _GitCommitSeven;
|
||||
public string InboundApiAllowedIPList => _InboundApiAllowedIPList;
|
||||
public string MonARessource => _MonARessource;
|
||||
public string OIExportPath => _OIExportPath;
|
||||
public string URLs => _URLs;
|
||||
public string WorkingDirectoryName => _WorkingDirectoryName;
|
||||
|
||||
[JsonConstructor]
|
||||
public AppSettings(string apiLoggingContentTypes, string apiLoggingPathPrefixes, string apiLogPath, string attachmentPath, string buildNumber, string company, string connectionString, string gitCommitSeven, string inboundApiAllowedIPList, string monARessource, string oiExportPath, string urls, string workingDirectoryName)
|
||||
{
|
||||
_ApiLoggingContentTypes = apiLoggingContentTypes;
|
||||
_ApiLoggingPathPrefixes = apiLoggingPathPrefixes;
|
||||
_ApiLogPath = apiLogPath;
|
||||
_AttachmentPath = attachmentPath;
|
||||
_BuildNumber = buildNumber;
|
||||
_Company = company;
|
||||
_ConnectionString = connectionString;
|
||||
_GitCommitSeven = gitCommitSeven;
|
||||
_InboundApiAllowedIPList = inboundApiAllowedIPList;
|
||||
_MonARessource = monARessource;
|
||||
_OIExportPath = oiExportPath;
|
||||
_URLs = urls;
|
||||
_WorkingDirectoryName = workingDirectoryName;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
string result = JsonSerializer.Serialize(this, new JsonSerializerOptions() { WriteIndented = true });
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
46
Archive/Models/Binder/AppSettings.cs
Normal file
46
Archive/Models/Binder/AppSettings.cs
Normal file
@ -0,0 +1,46 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Text.Json;
|
||||
|
||||
namespace OI.Metrology.Archive.Models.Binder;
|
||||
|
||||
public class AppSettings
|
||||
{
|
||||
|
||||
[Display(Name = "Api Logging Content Types"), Required] public string ApiLoggingContentTypes { get; set; }
|
||||
[Display(Name = "Api Logging Path Prefixes"), Required] public string ApiLoggingPathPrefixes { get; set; }
|
||||
[Display(Name = "Api Log Path"), Required] public string ApiLogPath { get; set; }
|
||||
[Display(Name = "Attachment Path"), Required] public string AttachmentPath { get; set; }
|
||||
[Display(Name = "Build Number"), Required] public string BuildNumber { get; set; }
|
||||
[Display(Name = "Company"), Required] public string Company { get; set; }
|
||||
[Display(Name = "Connection String"), Required] public string ConnectionString { get; set; }
|
||||
[Display(Name = "Git Commit Seven"), Required] public string GitCommitSeven { get; set; }
|
||||
[Display(Name = "Inbound Api Allowed IP List"), Required] public string InboundApiAllowedIPList { get; set; }
|
||||
[Display(Name = "MonA Ressource"), Required] public string MonARessource { get; set; }
|
||||
[Display(Name = "OI Export Path"), Required] public string OIExportPath { get; set; }
|
||||
[Display(Name = "URLs"), Required] public string URLs { get; set; }
|
||||
[Display(Name = "Working Directory Name"), Required] public string WorkingDirectoryName { get; set; }
|
||||
|
||||
public AppSettings()
|
||||
{
|
||||
ApiLoggingContentTypes = string.Empty;
|
||||
ApiLoggingPathPrefixes = string.Empty;
|
||||
ApiLogPath = string.Empty;
|
||||
AttachmentPath = string.Empty;
|
||||
BuildNumber = string.Empty;
|
||||
Company = string.Empty;
|
||||
ConnectionString = string.Empty;
|
||||
GitCommitSeven = string.Empty;
|
||||
InboundApiAllowedIPList = string.Empty;
|
||||
MonARessource = string.Empty;
|
||||
OIExportPath = string.Empty;
|
||||
URLs = string.Empty;
|
||||
WorkingDirectoryName = string.Empty;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
string result = JsonSerializer.Serialize(this, new JsonSerializerOptions() { WriteIndented = true });
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
44
Archive/Models/Stateless/AppSettings.cs
Normal file
44
Archive/Models/Stateless/AppSettings.cs
Normal file
@ -0,0 +1,44 @@
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Text.Json;
|
||||
|
||||
namespace OI.Metrology.Archive.Models.Stateless;
|
||||
|
||||
public abstract class AppSettings
|
||||
{
|
||||
|
||||
#nullable enable
|
||||
|
||||
public static Models.AppSettings Get(IConfigurationRoot configurationRoot)
|
||||
{
|
||||
Models.AppSettings? result;
|
||||
Binder.AppSettings appSettings = configurationRoot.Get<Binder.AppSettings>();
|
||||
string json = JsonSerializer.Serialize(appSettings, new JsonSerializerOptions() { WriteIndented = true });
|
||||
result = JsonSerializer.Deserialize<Models.AppSettings>(json);
|
||||
if (result is null)
|
||||
throw new Exception(json);
|
||||
if (string.IsNullOrEmpty(result.Company))
|
||||
throw new Exception(json);
|
||||
string jsonThis = result.ToString();
|
||||
if (jsonThis != json)
|
||||
{
|
||||
int? check = null;
|
||||
int min = new int[] { json.Length, jsonThis.Length }.Min();
|
||||
for (int i = 0; i < min; i++)
|
||||
{
|
||||
if (json[i] == jsonThis[i])
|
||||
continue;
|
||||
check = i;
|
||||
break;
|
||||
}
|
||||
if (check is null)
|
||||
throw new Exception();
|
||||
string a = json[..check.Value].Split(',')[^1];
|
||||
string b = json[check.Value..].Split(',')[0];
|
||||
throw new Exception($"{a}{b}");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
@ -5,10 +5,13 @@ using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.Hosting.WindowsServices;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using OI.Metrology.Archive.Models;
|
||||
using OI.Metrology.Archive.Repositories;
|
||||
using OI.Metrology.Archive.Services;
|
||||
using OI.Metrology.Shared.Models;
|
||||
using OI.Metrology.Shared.Repositories;
|
||||
using OI.Metrology.Shared.Services;
|
||||
using Serilog;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
@ -18,52 +21,61 @@ namespace OI.Metrology.Archive;
|
||||
public class Program
|
||||
{
|
||||
|
||||
private static string GetWebRoot()
|
||||
private static (string, WebApplicationOptions) Get(string[] args)
|
||||
{
|
||||
string result;
|
||||
string webRootPath;
|
||||
Assembly assembly = Assembly.GetExecutingAssembly();
|
||||
string assemblyName = assembly.GetName()?.Name;
|
||||
if (string.IsNullOrEmpty(assemblyName))
|
||||
throw new Exception();
|
||||
string net6 = "net6.0";
|
||||
string baseAssemblyName = assemblyName.Split('.')[0];
|
||||
if (WindowsServiceHelpers.IsWindowsService())
|
||||
result = Path.Combine("D:", net6, baseAssemblyName, "wwwroot");
|
||||
webRootPath = Path.Combine(AppContext.BaseDirectory, "wwwroot");
|
||||
else
|
||||
result = Path.Combine(AppContext.BaseDirectory.Split(baseAssemblyName)[0], baseAssemblyName, "Client", "bin", "Debug", net6, "wwwroot");
|
||||
if (!Directory.Exists(result))
|
||||
result = string.Empty;
|
||||
return result;
|
||||
webRootPath = Path.Combine(AppContext.BaseDirectory.Split(baseAssemblyName)[0], baseAssemblyName, "wwwroot");
|
||||
if (!Directory.Exists(webRootPath))
|
||||
webRootPath = string.Empty;
|
||||
WebApplicationOptions webApplicationOptions = new()
|
||||
{
|
||||
Args = args,
|
||||
ContentRootPath = AppContext.BaseDirectory,
|
||||
WebRootPath = webRootPath
|
||||
};
|
||||
return new(assemblyName, webApplicationOptions);
|
||||
}
|
||||
|
||||
public static int Main(string[] args)
|
||||
{
|
||||
WebApplicationOptions options = new()
|
||||
{
|
||||
Args = args,
|
||||
ContentRootPath = AppContext.BaseDirectory,
|
||||
WebRootPath = GetWebRoot()
|
||||
};
|
||||
WebApplicationBuilder webApplicationBuilder = WebApplication.CreateBuilder(options);
|
||||
LoggerConfiguration loggerConfiguration = new();
|
||||
(string assemblyName, WebApplicationOptions webApplicationOptions) = Get(args);
|
||||
WebApplicationBuilder webApplicationBuilder = WebApplication.CreateBuilder(webApplicationOptions);
|
||||
_ = webApplicationBuilder.Configuration.AddUserSecrets<Program>();
|
||||
AppSettings appSettings = Models.Stateless.AppSettings.Get(webApplicationBuilder.Configuration);
|
||||
if (string.IsNullOrEmpty(appSettings.WorkingDirectoryName))
|
||||
throw new Exception("Working directory name must have a value!");
|
||||
string workingDirectory = IWorkingDirectory.GetWorkingDirectory(assemblyName, appSettings.WorkingDirectoryName);
|
||||
Environment.SetEnvironmentVariable(nameof(workingDirectory), workingDirectory);
|
||||
_ = ConfigurationLoggerConfigurationExtensions.Configuration(loggerConfiguration.ReadFrom, webApplicationBuilder.Configuration);
|
||||
_ = SerilogHostBuilderExtensions.UseSerilog(webApplicationBuilder.Host);
|
||||
Log.Logger = loggerConfiguration.CreateLogger();
|
||||
Serilog.ILogger log = Log.ForContext<Program>();
|
||||
try
|
||||
{
|
||||
// this prevents validation errors from being handled by ASP.NET and not hitting our custom error handle
|
||||
_ = webApplicationBuilder.Services.Configure<ApiBehaviorOptions>(options => options.SuppressModelStateInvalidFilter = true);
|
||||
_ = webApplicationBuilder.Services.AddControllersWithViews();
|
||||
_ = new MetrologyRepo(new SQLDbConnectionFactory(webApplicationBuilder.Configuration), null);
|
||||
_ = webApplicationBuilder.Services.AddSingleton<IDbConnectionFactory, SQLDbConnectionFactory>();
|
||||
_ = webApplicationBuilder.Services.AddScoped<IMetrologyRepo, MetrologyRepo>();
|
||||
_ = new MetrologyRepo(new SQLDbConnectionFactory(appSettings), null);
|
||||
_ = webApplicationBuilder.Services.AddDistributedMemoryCache();
|
||||
_ = webApplicationBuilder.Services.AddMemoryCache();
|
||||
_ = webApplicationBuilder.Services.AddSingleton<AppSettings, AppSettings>(_ => appSettings);
|
||||
_ = webApplicationBuilder.Services.AddScoped<IAttachmentsService, AttachmentsService>();
|
||||
_ = webApplicationBuilder.Services.AddScoped<IInboundDataService, InboundDataService>();
|
||||
_ = webApplicationBuilder.Services.AddMemoryCache();
|
||||
_ = webApplicationBuilder.Services.AddDistributedMemoryCache();
|
||||
_ = webApplicationBuilder.Services.AddScoped<IMetrologyRepo, MetrologyRepo>();
|
||||
_ = webApplicationBuilder.Services.AddSingleton<IDbConnectionFactory, SQLDbConnectionFactory>();
|
||||
_ = webApplicationBuilder.Services.AddSwaggerGen();
|
||||
_ = webApplicationBuilder.Services.AddSession(sessionOptions =>
|
||||
{
|
||||
// Set a short timeout for easy testing.
|
||||
sessionOptions.IdleTimeout = TimeSpan.FromSeconds(2000);
|
||||
sessionOptions.Cookie.HttpOnly = true;
|
||||
// Make the session cookie essential
|
||||
sessionOptions.Cookie.IsEssential = true;
|
||||
}
|
||||
);
|
||||
@ -77,26 +89,41 @@ public class Program
|
||||
});
|
||||
}
|
||||
WebApplication webApplication = webApplicationBuilder.Build();
|
||||
if (webApplicationBuilder.Environment.IsDevelopment())
|
||||
if (!webApplicationBuilder.Environment.IsDevelopment())
|
||||
{
|
||||
_ = webApplication.UseExceptionHandler("/Error");
|
||||
_ = webApplication.UseHsts();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (string.IsNullOrEmpty(appSettings.URLs))
|
||||
{
|
||||
Environment.ExitCode = -1;
|
||||
webApplication.Lifetime.StopApplication();
|
||||
}
|
||||
_ = webApplication.UseSwagger();
|
||||
_ = webApplication.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "Archive V1"));
|
||||
}
|
||||
_ = webApplication.Lifetime.ApplicationStopped.Register(Log.CloseAndFlush);
|
||||
_ = ApplicationBuilderSerilogClientExtensions.UseSerilogIngestion(webApplication);
|
||||
_ = SerilogApplicationBuilderExtensions.UseSerilogRequestLogging(webApplication);
|
||||
_ = webApplication.UseStaticFiles();
|
||||
_ = webApplication.UseSession();
|
||||
_ = webApplication.UseHttpsRedirection();
|
||||
_ = webApplication.UseMiddleware<ApiLoggingMiddleware>();
|
||||
_ = webApplication.MapControllers();
|
||||
log.Information("Starting Web Application");
|
||||
webApplication.Run();
|
||||
return 0;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine(ex.Message);
|
||||
log.Fatal(ex, "Host terminated unexpectedly");
|
||||
return 1;
|
||||
}
|
||||
finally
|
||||
{
|
||||
Log.CloseAndFlush();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -14,17 +14,16 @@ namespace OI.Metrology.Archive.Repositories;
|
||||
|
||||
public class MetrologyRepo : IMetrologyRepo
|
||||
{
|
||||
private IDbConnectionFactory DBConnectionFactory { get; }
|
||||
private readonly IDbConnectionFactory _DBConnectionFactory;
|
||||
private readonly IMemoryCache _Cache;
|
||||
|
||||
public MetrologyRepo(IDbConnectionFactory dbConnectionFactory, IMemoryCache memoryCache)
|
||||
{
|
||||
DBConnectionFactory = dbConnectionFactory;
|
||||
_DBConnectionFactory = dbConnectionFactory;
|
||||
_Cache = memoryCache;
|
||||
}
|
||||
|
||||
private DbConnection GetDbConnection() => DBConnectionFactory.GetDbConnection(Constants.ConnStringName);
|
||||
private DbConnection GetDbConnection2() => DBConnectionFactory.GetDbConnection(Constants.ConnStringName2);
|
||||
private DbConnection GetDbConnection() => _DBConnectionFactory.GetDbConnection();
|
||||
|
||||
protected DbProviderFactory GetDbProviderFactory(IDbConnection conn) => DbProviderFactories.GetFactory(conn.GetType().Namespace);
|
||||
|
||||
@ -57,19 +56,6 @@ public class MetrologyRepo : IMetrologyRepo
|
||||
string cacheKey = "GetToolTypes";
|
||||
if (_Cache.TryGetValue(cacheKey, out cached))
|
||||
return cached;
|
||||
//List<string> r = new List<string>();
|
||||
//r.Add("BioRad");
|
||||
//r.Add("CDE");
|
||||
//r.Add("Tencor");
|
||||
//r.Add("MercuryProbe");
|
||||
//r.Add("StratusBioRad");
|
||||
//r.Add("TencorSP1");
|
||||
|
||||
//CacheItem(cacheKey, r);
|
||||
|
||||
//return r;
|
||||
|
||||
//var conn =
|
||||
|
||||
using DbConnection conn = GetDbConnection();
|
||||
IEnumerable<ToolType> r = conn.Query<ToolType>("SELECT * FROM ToolType");
|
||||
@ -95,7 +81,7 @@ public class MetrologyRepo : IMetrologyRepo
|
||||
|
||||
return r;
|
||||
}
|
||||
//Changed by Jonathan : Changed this as the table ToolType doesn't exist in the Metrology_Archive DB
|
||||
// Changed by Jonathan : Changed this as the table ToolType doesn't exist in the Metrology_Archive DB
|
||||
public ToolType GetToolTypeByID(int id)
|
||||
{
|
||||
ToolType cached;
|
||||
@ -103,7 +89,6 @@ public class MetrologyRepo : IMetrologyRepo
|
||||
if (_Cache.TryGetValue(cacheKey, out cached))
|
||||
return cached;
|
||||
|
||||
//using (var conn = GetDbConnection2())
|
||||
using DbConnection conn = GetDbConnection();
|
||||
ToolType r = conn.QueryFirstOrDefault<ToolType>(
|
||||
"SELECT * FROM ToolType WHERE ID = @id",
|
||||
@ -113,12 +98,10 @@ public class MetrologyRepo : IMetrologyRepo
|
||||
|
||||
return r;
|
||||
}
|
||||
//Changed by Jonathan : Changed this to look at Metrology DB because table ToolTypeMetaData does not exist in Metrology_Archive. This still fails when BioRad is the tool.
|
||||
// Changed by Jonathan : Changed this to look at Metrology DB because table ToolTypeMetaData does not exist in Metrology_Archive. This still fails when BioRad is the tool.
|
||||
public IEnumerable<ToolTypeMetadata> GetToolTypeMetadataByToolTypeID(int id)
|
||||
{
|
||||
string cacheKey = "GetToolTypeMetadataByToolTypeID_" + id.ToString();
|
||||
//if (_cache.TryGetValue(cacheKey, out cached))
|
||||
//return cached;
|
||||
|
||||
using DbConnection conn = GetDbConnection();
|
||||
IEnumerable<ToolTypeMetadata> r = conn.Query<ToolTypeMetadata>(
|
||||
@ -335,8 +318,8 @@ public class MetrologyRepo : IMetrologyRepo
|
||||
_ = sb.AppendFormat(" FROM [{0}] ", tableName);
|
||||
return sb.ToString();
|
||||
}
|
||||
//Set DB Connection based on isArchive flag, for prod need to set isArchive outside of this function.
|
||||
public DataTable GetHeaders(int toolTypeId, DateTime? startTime, DateTime? endTime, int? pageNo, int? pageSize, long? headerId, out long totalRecords, bool isArchive)
|
||||
|
||||
public DataTable GetHeaders(int toolTypeId, DateTime? startTime, DateTime? endTime, int? pageNo, int? pageSize, long? headerId, out long totalRecords)
|
||||
{
|
||||
ToolType tt = GetToolTypeByID(toolTypeId);
|
||||
if (tt == null)
|
||||
@ -348,14 +331,7 @@ public class MetrologyRepo : IMetrologyRepo
|
||||
|
||||
DataTable dt = new();
|
||||
|
||||
//bool isArchive = true;
|
||||
|
||||
DbConnection conn = GetDbConnection();
|
||||
if (isArchive == true)
|
||||
{
|
||||
conn = GetDbConnection2();
|
||||
}
|
||||
|
||||
using (conn)
|
||||
{
|
||||
System.Text.StringBuilder sb = new();
|
||||
@ -433,10 +409,9 @@ public class MetrologyRepo : IMetrologyRepo
|
||||
|
||||
return dt;
|
||||
}
|
||||
//Go Here Next
|
||||
public DataTable GetData(int toolTypeId, long headerid, bool isArchive)
|
||||
// Go Here Next
|
||||
public DataTable GetData(int toolTypeId, long headerid)
|
||||
{
|
||||
//isArchive = true;
|
||||
ToolType tt = GetToolTypeByID(toolTypeId);
|
||||
if (tt == null)
|
||||
throw new Exception("Invalid tool type ID");
|
||||
@ -448,11 +423,6 @@ public class MetrologyRepo : IMetrologyRepo
|
||||
DataTable dt = new();
|
||||
|
||||
DbConnection conn = GetDbConnection();
|
||||
if (isArchive == true)
|
||||
{
|
||||
conn = GetDbConnection2();
|
||||
}
|
||||
|
||||
using (conn)
|
||||
{
|
||||
System.Text.StringBuilder sb = new();
|
||||
@ -467,7 +437,6 @@ public class MetrologyRepo : IMetrologyRepo
|
||||
DbCommand cmd = factory.CreateCommand();
|
||||
|
||||
_ = sb.Append("WHERE [HeaderID] = @HeaderID ");
|
||||
//sb.Append("WHERE [OriginID] = @HeaderID ");
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(tt.DataGridSortBy))
|
||||
{
|
||||
@ -537,7 +506,7 @@ public class MetrologyRepo : IMetrologyRepo
|
||||
|
||||
return dt;
|
||||
}
|
||||
public string GetAttachmentInsertDateByGUID(String tableName, Guid attachmentId)
|
||||
public string GetAttachmentInsertDateByGUID(string tableName, Guid attachmentId)
|
||||
{
|
||||
using DbConnection conn = GetDbConnection();
|
||||
string sql = "";
|
||||
@ -554,7 +523,6 @@ public class MetrologyRepo : IMetrologyRepo
|
||||
}
|
||||
public DataTable GetDataSharePoint(int toolTypeId, string headerid)
|
||||
{
|
||||
//isArchive = true;
|
||||
ToolType tt = GetToolTypeByID(toolTypeId);
|
||||
if (tt == null)
|
||||
throw new Exception("Invalid tool type ID");
|
||||
@ -566,10 +534,6 @@ public class MetrologyRepo : IMetrologyRepo
|
||||
DataTable dt = new();
|
||||
|
||||
DbConnection conn = GetDbConnection();
|
||||
//if (isArchive == true)
|
||||
//{
|
||||
// conn = GetDbConnection2();
|
||||
//}
|
||||
|
||||
using (conn)
|
||||
{
|
||||
@ -585,15 +549,12 @@ public class MetrologyRepo : IMetrologyRepo
|
||||
DbCommand cmd = factory.CreateCommand();
|
||||
|
||||
_ = sb.Append("WHERE [Title] LIKE '%" + headerid + "%' ");
|
||||
//sb.Append("WHERE [OriginID] = @HeaderID ");
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(tt.DataGridSortBy))
|
||||
{
|
||||
_ = sb.AppendFormat("ORDER BY {0} ", tt.DataGridSortBy);
|
||||
}
|
||||
|
||||
//AddParameter(cmd, "@HeaderID", headerid);
|
||||
|
||||
cmd.Connection = conn;
|
||||
cmd.CommandText = sb.ToString();
|
||||
cmd.CommandType = CommandType.Text;
|
||||
@ -716,18 +677,13 @@ public class MetrologyRepo : IMetrologyRepo
|
||||
return ds;
|
||||
}
|
||||
|
||||
public IEnumerable<HeaderCommon> GetHeaderTitles(int toolTypeId, int? pageNo, int? pageSize, out long totalRecords, bool isArchive)
|
||||
public IEnumerable<HeaderCommon> GetHeaderTitles(int toolTypeId, int? pageNo, int? pageSize, out long totalRecords)
|
||||
{
|
||||
ToolType tt = GetToolTypeByID(toolTypeId);
|
||||
if (tt == null)
|
||||
throw new Exception("Invalid tool type ID");
|
||||
|
||||
DbConnection conn = GetDbConnection();
|
||||
if (isArchive == true)
|
||||
{
|
||||
conn = GetDbConnection2();
|
||||
}
|
||||
|
||||
using (conn)
|
||||
{
|
||||
string sql = $"SELECT ID, InsertDate, AttachmentID, Title, [Date] FROM {tt.HeaderTableName} ORDER BY [Date] DESC ";
|
||||
@ -753,7 +709,7 @@ public class MetrologyRepo : IMetrologyRepo
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerable<KeyValuePair<string, string>> GetHeaderFields(int toolTypeId, long headerid, bool isArchive)
|
||||
public IEnumerable<KeyValuePair<string, string>> GetHeaderFields(int toolTypeId, long headerid)
|
||||
{
|
||||
ToolType tt = GetToolTypeByID(toolTypeId);
|
||||
if (tt == null)
|
||||
@ -766,11 +722,6 @@ public class MetrologyRepo : IMetrologyRepo
|
||||
List<KeyValuePair<string, string>> r = new();
|
||||
|
||||
DbConnection conn = GetDbConnection();
|
||||
if (isArchive == true)
|
||||
{
|
||||
conn = GetDbConnection2();
|
||||
}
|
||||
|
||||
using (conn)
|
||||
{
|
||||
DbProviderFactory factory = GetDbProviderFactory(conn);
|
||||
@ -811,7 +762,7 @@ public class MetrologyRepo : IMetrologyRepo
|
||||
using DbConnection conn = GetDbConnection();
|
||||
return conn.Query<AwaitingDispo>("GetAwaitingDispo", commandType: CommandType.StoredProcedure);
|
||||
}
|
||||
//Jonathan changed this to remove the reviewDate update on the database.
|
||||
// Jonathan changed this to remove the reviewDate update on the database.
|
||||
public int UpdateReviewDate(int toolTypeId, long headerId, bool clearDate)
|
||||
{
|
||||
ToolType tt = GetToolTypeByID(toolTypeId);
|
||||
@ -821,7 +772,7 @@ public class MetrologyRepo : IMetrologyRepo
|
||||
using DbConnection conn = GetDbConnection();
|
||||
if (clearDate)
|
||||
{
|
||||
//if it's already past the 6 hour window, then it won't show in queue anyway, so need to return value so we can show that
|
||||
// if it's already past the 6 hour window, then it won't show in queue anyway, so need to return value so we can show that
|
||||
string sql = $"SELECT DATEDIFF(HH, INSERTDATE, GETDATE()) FROM [{tt.HeaderTableName}] WHERE ID = @HeaderID";
|
||||
int hrs = conn.ExecuteScalar<int>(sql, param: new { HeaderId = headerId });
|
||||
_ = conn.Execute($"UPDATE [{tt.HeaderTableName}] SET ReviewDate = NULL WHERE ID = @HeaderID", new { HeaderID = headerId });
|
||||
@ -829,7 +780,6 @@ public class MetrologyRepo : IMetrologyRepo
|
||||
}
|
||||
else
|
||||
{
|
||||
//conn.Execute($"UPDATE [{tt.HeaderTableName}] SET ReviewDate = GETDATE() WHERE ID = @HeaderID", new { HeaderID = headerId });
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
@ -857,4 +807,9 @@ public class MetrologyRepo : IMetrologyRepo
|
||||
$"SELECT TOP 1 AttachmentID FROM [{tt.DataTableName}] WHERE Title = @Title ORDER BY InsertDate DESC";
|
||||
return conn.ExecuteScalar<Guid>(sql, param: new { Title = title });
|
||||
}
|
||||
|
||||
string IMetrologyRepo.GetHeaderInsertDate(int toolTypeId, long headerId) => throw new NotImplementedException();
|
||||
void IMetrologyRepo.SetHeaderDirName(string tableName, long headerId, string dateDir) => throw new NotImplementedException();
|
||||
string IMetrologyRepo.GetDataInsertDate(int toolTypeId, long headerId, string title) => throw new NotImplementedException();
|
||||
void IMetrologyRepo.SetDataDirName(string tableName, long headerId, string title, string dateDir) => throw new NotImplementedException();
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using OI.Metrology.Archive.Models;
|
||||
using OI.Metrology.Shared.Repositories;
|
||||
using System;
|
||||
using System.Data.Common;
|
||||
@ -8,22 +8,21 @@ namespace OI.Metrology.Archive.Repositories;
|
||||
|
||||
public class SQLDbConnectionFactory : IDbConnectionFactory
|
||||
{
|
||||
private IConfiguration Config { get; }
|
||||
private readonly AppSettings _AppSettings;
|
||||
|
||||
public SQLDbConnectionFactory(IConfiguration config) => Config = config;
|
||||
public SQLDbConnectionFactory(AppSettings appSettings) => _AppSettings = appSettings;
|
||||
|
||||
public DbConnection GetDbConnection(String connStringName)
|
||||
public DbConnection GetDbConnection()
|
||||
{
|
||||
DbProviderFactories.RegisterFactory(
|
||||
typeof(SqlConnection).Namespace,
|
||||
SqlClientFactory.Instance);
|
||||
|
||||
string connStr = Config?.GetConnectionString(connStringName);
|
||||
if (connStr is null)
|
||||
throw new Exception("Connection string is missing: " + connStringName);
|
||||
if (string.IsNullOrEmpty(_AppSettings.ConnectionString))
|
||||
throw new Exception("Connection string is missing");
|
||||
|
||||
DbConnection c = SqlClientFactory.Instance.CreateConnection();
|
||||
c.ConnectionString = connStr;
|
||||
c.ConnectionString = _AppSettings.ConnectionString;
|
||||
c.Open();
|
||||
return c;
|
||||
}
|
||||
|
@ -1,10 +1,10 @@
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using System;
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
|
||||
namespace OI.Metrology.Archive.Services;
|
||||
|
||||
using OI.Metrology.Archive.Models;
|
||||
using OI.Metrology.Shared.DataModels;
|
||||
using OI.Metrology.Shared.Repositories;
|
||||
using OI.Metrology.Shared.Services;
|
||||
@ -12,19 +12,17 @@ using System.Data.SqlClient;
|
||||
|
||||
public class AttachmentsService : IAttachmentsService
|
||||
{
|
||||
private IConfiguration Config { get; }
|
||||
|
||||
protected IMetrologyRepo _Repo;
|
||||
private readonly IMetrologyRepo _Repo;
|
||||
private readonly AppSettings _AppSettings;
|
||||
|
||||
public AttachmentsService(IConfiguration config, IMetrologyRepo repo)
|
||||
public AttachmentsService(AppSettings appSettings, IMetrologyRepo repo)
|
||||
{
|
||||
Config = config;
|
||||
_Repo = repo;
|
||||
_AppSettings = appSettings;
|
||||
}
|
||||
protected Stream GetAttachmentStream(String tableName, Guid attachmentId, string filename)
|
||||
protected Stream GetAttachmentStream(string tableName, Guid attachmentId, string filename)
|
||||
{
|
||||
string attachmentsRootPath = Config[Constants.AttachmentPathKey];
|
||||
|
||||
if (attachmentId.Equals(Guid.Empty))
|
||||
throw new Exception("No attachments found");
|
||||
|
||||
@ -36,12 +34,12 @@ public class AttachmentsService : IAttachmentsService
|
||||
string workWeek = "WW" + weekNum.ToString("00");
|
||||
string dateDir = year + @"\" + workWeek;
|
||||
|
||||
string fullPath = Path.Combine(attachmentsRootPath, tableName + "_", dateDir, attachmentId.ToString(), filename);
|
||||
string fullPath = Path.Combine(_AppSettings.AttachmentPath, tableName + "_", dateDir, attachmentId.ToString(), filename);
|
||||
|
||||
//Check to see if file exists in the "New" directory structure, if not change the path back to the old. and check there
|
||||
// Check to see if file exists in the "New" directory structure, if not change the path back to the old. and check there
|
||||
if (!File.Exists(fullPath))
|
||||
{
|
||||
fullPath = Path.Combine(attachmentsRootPath, tableName, attachmentId.ToString(), filename);
|
||||
fullPath = Path.Combine(_AppSettings.AttachmentPath, tableName, attachmentId.ToString(), filename);
|
||||
}
|
||||
|
||||
if (!File.Exists(fullPath))
|
||||
@ -49,40 +47,20 @@ public class AttachmentsService : IAttachmentsService
|
||||
|
||||
return new FileStream(fullPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
|
||||
}
|
||||
//protected System.IO.Stream GetAttachmentStream(String tableName, Guid attachmentId, string filename)
|
||||
//{
|
||||
|
||||
// //This part seems to be key
|
||||
// var attachmentsRootPath = _config[Constants.AttachmentPathKey];
|
||||
|
||||
// //if (attachmentId.Equals(Guid.Empty))
|
||||
// //throw new Exception("No attachments found");
|
||||
// //string list = Directory.GetDirectories(attachmentsRootPath).Where(s => s.Contains(attachmentId.ToString())).SingleOrDefault();
|
||||
|
||||
// //var fullPath = list;
|
||||
// var fullPath = System.IO.Path.Combine(attachmentsRootPath, tableName, attachmentId.ToString(), filename);
|
||||
|
||||
// if (!System.IO.File.Exists(fullPath))
|
||||
// throw new Exception("File not found " + fullPath);
|
||||
|
||||
// return new System.IO.FileStream(fullPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
|
||||
//}
|
||||
protected Stream GetAttachmentStreamArchive(String tableName, Guid attachmentId, string filename)
|
||||
protected Stream GetAttachmentStreamArchive(string tableName, Guid attachmentId, string filename)
|
||||
{
|
||||
|
||||
//This part seems to be key
|
||||
string attachmentsRootPath = Config[Constants.AttachmentPathKey];
|
||||
|
||||
if (attachmentId.Equals(Guid.Empty))
|
||||
throw new Exception("No attachments found");
|
||||
|
||||
string fullPath = Path.Combine(attachmentsRootPath, tableName, "2019\\09", attachmentId.ToString(), filename);
|
||||
string fullPath = Path.Combine(_AppSettings.AttachmentPath, tableName, "2019\\09", attachmentId.ToString(), filename);
|
||||
|
||||
if (!File.Exists(fullPath))
|
||||
throw new Exception("File not found");
|
||||
|
||||
return new FileStream(fullPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
|
||||
}
|
||||
|
||||
public Stream GetAttachmentStreamByTitle(ToolType toolType, bool header, string title, string filename)
|
||||
{
|
||||
if (toolType == null)
|
||||
@ -98,7 +76,6 @@ public class AttachmentsService : IAttachmentsService
|
||||
using (SqlConnection connection = new(connectionString))
|
||||
{
|
||||
SqlCommand command = new(queryString, connection);
|
||||
//command.Parameters.AddWithValue("@attachmentId", attachmentId);
|
||||
connection.Open();
|
||||
SqlDataReader reader = command.ExecuteReader();
|
||||
try
|
||||
@ -112,7 +89,6 @@ public class AttachmentsService : IAttachmentsService
|
||||
}
|
||||
finally
|
||||
{
|
||||
// Always call Close when done reading.
|
||||
reader.Close();
|
||||
}
|
||||
}
|
||||
@ -121,14 +97,8 @@ public class AttachmentsService : IAttachmentsService
|
||||
{
|
||||
_ = "0" + SearchMonth;
|
||||
}
|
||||
|
||||
_ = SearchDate.Year.ToString();
|
||||
|
||||
_ = Config[Constants.AttachmentPathKey];
|
||||
|
||||
string tableName;
|
||||
|
||||
//var attachmentsRootPath = "\\\\messv02ecc1.ec.local\\EC_Metrology_Si\\MetrologyAttachments\\TencorRunData\\2019\\09";
|
||||
Guid attachmentId;
|
||||
if (header)
|
||||
{
|
||||
@ -140,7 +110,6 @@ public class AttachmentsService : IAttachmentsService
|
||||
tableName = toolType.DataTableName;
|
||||
attachmentId = _Repo.GetDataAttachmentIDByTitle(toolType.ID, title);
|
||||
}
|
||||
|
||||
return GetAttachmentStream(tableName, attachmentId, filename);
|
||||
}
|
||||
|
||||
@ -148,66 +117,18 @@ public class AttachmentsService : IAttachmentsService
|
||||
{
|
||||
if (toolType == null)
|
||||
throw new Exception("Invalid tool type");
|
||||
|
||||
/*string queryString = "SELECT * FROM " + toolType.DataTableName + " WHERE AttachmentId = @attachmentId";
|
||||
if (header)
|
||||
{
|
||||
queryString = "SELECT * FROM " + toolType.HeaderTableName + " WHERE AttachmentId = '" + attachmentId + "'";
|
||||
}
|
||||
DateTime SearchDate = new DateTime();
|
||||
string connectionString = @"Server=messv01ec.ec.local\PROD1,53959;Database=Metrology_Archive;Integrated Security=True";
|
||||
using (SqlConnection connection = new SqlConnection(connectionString))
|
||||
{
|
||||
SqlCommand command = new SqlCommand(queryString, connection);
|
||||
command.Parameters.AddWithValue("@attachmentId", attachmentId);
|
||||
connection.Open();
|
||||
SqlDataReader reader = command.ExecuteReader();
|
||||
try
|
||||
{
|
||||
while (reader.Read())
|
||||
{
|
||||
Console.WriteLine(string.Format("{0}", reader["InsertDate"]));// etc
|
||||
//string test = string.Format("{0}", reader["InsertDate"]);
|
||||
SearchDate = Convert.ToDateTime(string.Format("{0}", reader["Date"]));
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
// Always call Close when done reading.
|
||||
reader.Close();
|
||||
}
|
||||
}
|
||||
string SearchMonth = SearchDate.Month.ToString();
|
||||
if (SearchDate.Month < 10)
|
||||
{
|
||||
SearchMonth = "0" + SearchMonth;
|
||||
}
|
||||
string SearchYear = SearchDate.Year.ToString();*/
|
||||
//string DateSearchTermin = +""+
|
||||
|
||||
_ = Config[Constants.AttachmentPathKey];
|
||||
|
||||
string tableName;
|
||||
|
||||
if (header)
|
||||
tableName = toolType.HeaderTableName;
|
||||
else
|
||||
tableName = toolType.DataTableName;
|
||||
|
||||
//System.IO.Stream test = GetAttachmentStream(tableName, attachmentId, filename, SearchYear);
|
||||
|
||||
return GetAttachmentStream(tableName, attachmentId, filename);
|
||||
//return test;
|
||||
}
|
||||
public Stream GetAttachmentStreamByAttachmentIdArchive(ToolType toolType, bool header, Guid attachmentId, string filename)
|
||||
{
|
||||
if (toolType == null)
|
||||
throw new Exception("Invalid tool type");
|
||||
|
||||
_ = Config[Constants.AttachmentPathKey];
|
||||
|
||||
string tableName;
|
||||
|
||||
if (header)
|
||||
tableName = toolType.HeaderTableName;
|
||||
else
|
||||
@ -216,7 +137,7 @@ string SearchYear = SearchDate.Year.ToString();*/
|
||||
return GetAttachmentStreamArchive(tableName, attachmentId, filename);
|
||||
}
|
||||
|
||||
public void SaveAttachment(ToolType toolType, long headerId, string dataUniqueId, string filename, Microsoft.AspNetCore.Http.IFormFile uploadedFile)
|
||||
private void SaveAttachment(ToolType toolType, long headerId, string dataUniqueId, string filename, Microsoft.AspNetCore.Http.IFormFile uploadedFile)
|
||||
{
|
||||
if (toolType == null)
|
||||
throw new Exception("Invalid tool type");
|
||||
@ -235,24 +156,16 @@ string SearchYear = SearchDate.Year.ToString();*/
|
||||
attachmentId = _Repo.GetDataAttachmentID(toolType.ID, headerId, dataUniqueId);
|
||||
tableName = toolType.DataTableName;
|
||||
}
|
||||
|
||||
if (Equals(attachmentId, Guid.Empty))
|
||||
throw new Exception("Invalid attachment ID");
|
||||
|
||||
string attachmentsRootPath = Config[Constants.AttachmentPathKey];
|
||||
|
||||
string directoryPath = Path.Combine(attachmentsRootPath, tableName, attachmentId.ToString());
|
||||
|
||||
string directoryPath = Path.Combine(_AppSettings.AttachmentPath, tableName, attachmentId.ToString());
|
||||
if (!Directory.Exists(directoryPath))
|
||||
_ = Directory.CreateDirectory(directoryPath);
|
||||
|
||||
string fullPath = Path.Combine(directoryPath, filename);
|
||||
|
||||
using (FileStream s = new(fullPath, FileMode.Create, FileAccess.ReadWrite, FileShare.None))
|
||||
{
|
||||
uploadedFile.CopyTo(s);
|
||||
}
|
||||
|
||||
trans.Complete();
|
||||
}
|
||||
|
||||
|
@ -10,7 +10,7 @@ namespace OI.Metrology.Archive.Services;
|
||||
|
||||
public class InboundDataService : IInboundDataService
|
||||
{
|
||||
protected IMetrologyRepo _Repo;
|
||||
private readonly IMetrologyRepo _Repo;
|
||||
|
||||
public InboundDataService(IMetrologyRepo repo) => _Repo = repo;
|
||||
|
||||
|
@ -18,22 +18,28 @@
|
||||
<form asp-controller="Export" asp-action="ExportData" method="post" class="form-inline">
|
||||
<div class="form-group">
|
||||
<label for="ToolType">Tool Type</label>
|
||||
<div class="form-control" id="ToolType"></div>
|
||||
<div class="form-control" id="ToolType" name="ToolType"></div>
|
||||
@Html.ValidationMessage("ToolType", new { @class = "text-danger" })
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="StartDate">Start Time</label>
|
||||
<div class="form-control mb-2 mr-sm-2" id="StartDateControl"></div>
|
||||
<div class="form-control mb-2 mr-sm-2" id="StartTimeControl"></div>
|
||||
@Html.ValidationMessage("StartDate", new { @class = "text-danger" })
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="EndDate">End Time</label>
|
||||
<div class="form-control mb-2 mr-sm-2" id="EndDateControl"></div>
|
||||
<div class="form-control mb-2 mr-sm-2" id="EndTimeControl"></div>
|
||||
</div>
|
||||
@Html.ValidationMessage("EndDate", new { @class = "text-danger" })
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<button type="submit" class="btn btn-primary">Export Data</button>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
@Html.ValidationMessage("Exception", new { @class = "text-danger" })
|
||||
</div>
|
||||
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
|
||||
|
||||
</form>
|
||||
@ -48,11 +54,7 @@
|
||||
textKey: "ToolTypeName",
|
||||
valueKey: "ID",
|
||||
mode: "dropdown",
|
||||
width: 150,
|
||||
itemsRendered: function (evt, ui) {
|
||||
LoadHeaderGrid();
|
||||
},
|
||||
selectionChanged: LoadHeaderGrid
|
||||
width: 150
|
||||
});
|
||||
|
||||
var startTime = new Date("@Model.StartTime.ToString("yyyy-MM-ddTHH:mm")");
|
||||
|
@ -1,5 +1,4 @@
|
||||
|
||||
@{
|
||||
@{
|
||||
ViewData["Title"] = "Awaiting Disposition";
|
||||
}
|
||||
|
||||
@ -45,12 +44,12 @@
|
||||
tabIndex: 1,
|
||||
features: [
|
||||
{ name: "Selection", mode: "row", multipleSelection: false },
|
||||
{ name: "Filtering", type: "local"},
|
||||
{ name: "Sorting", type:"local"},
|
||||
{ name: "Filtering", type: "local" },
|
||||
{ name: "Sorting", type: "local" },
|
||||
]
|
||||
});
|
||||
|
||||
function LoadRunInfo() {
|
||||
function LoadRunInfo() {
|
||||
var row = $("#grid").igGrid("selectedRow");
|
||||
if (row == null)
|
||||
return;
|
||||
|
@ -1,10 +1,10 @@
|
||||
|
||||
@{
|
||||
@{
|
||||
ViewData["Title"] = "Run Headers";
|
||||
}
|
||||
|
||||
<style>
|
||||
html, body {
|
||||
html,
|
||||
body {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
@ -12,7 +12,8 @@
|
||||
height: 90%;
|
||||
}
|
||||
|
||||
#HeaderGrid, #FieldsGrid {
|
||||
#HeaderGrid,
|
||||
#FieldsGrid {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
@ -70,7 +71,7 @@
|
||||
{ name: "Filtering", type: "local" }
|
||||
],
|
||||
columns: [
|
||||
{ key: "ID", dataType: "number", hidden: true},
|
||||
{ key: "ID", dataType: "number", hidden: true },
|
||||
{ key: "Title", dataType: "string", width: "80%" },
|
||||
{ key: "InsertDate", dataType: "date", format: "dateTime", width: "20%" }
|
||||
],
|
||||
|
@ -3,8 +3,8 @@
|
||||
ViewData["Title"] = "Run Information";
|
||||
}
|
||||
<style>
|
||||
#HeaderGridDiv, #
|
||||
Div {
|
||||
#HeaderGridDiv,
|
||||
# Div {
|
||||
font-size: 12px;
|
||||
}
|
||||
</style>
|
||||
@ -29,19 +29,6 @@
|
||||
<div class="form-group">
|
||||
<input class="btn btn-primary" type="button" value="Load Headers" id="LoadHeadersButton" />
|
||||
</div>
|
||||
@*<div class="form-group">
|
||||
<label class="form-check-label" for="chkAutoRefresh">
|
||||
Auto-Refresh
|
||||
</label>
|
||||
<input class="form-check-input" type="checkbox" id="chkAutoRefresh">
|
||||
</div>*@
|
||||
@*This checkbox below is for archive flag.*@
|
||||
@*<div class="form-group">
|
||||
<label class="form-check-label" for="isArchive">
|
||||
Archive
|
||||
</label>
|
||||
<input class="form-check-input" type="checkbox" id="isArchive">
|
||||
</div>*@
|
||||
</form>
|
||||
|
||||
<div style="height: 300px;" id="HeaderGridDiv">
|
||||
@ -202,18 +189,11 @@
|
||||
return;
|
||||
|
||||
$("#DataAttachmentFrame").prop("src", attachmentUrlBase + "/data/files/" + attachmentId + "/" + toolType.DisplayDataAttachment);
|
||||
//if (CheckArchive()) {
|
||||
// $("#DataAttachmentFrame").prop("src", attachmentUrlBase + "/data/files/" + attachmentId + "/" + toolType.DisplayDataAttachment);
|
||||
//}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
function LoadHeaderAttachment() {
|
||||
|
||||
|
||||
var toolTypeID = $("#ToolTypeID").text();
|
||||
|
||||
var attachmentUrlBase = '@Url.Content("~/api/tooltypes/")' + toolTypeID;
|
||||
var attachmentId = $("#HeaderAttachmentId").text();
|
||||
var dateToUse = new Date($("#HeaderDate").text());
|
||||
@ -222,37 +202,18 @@
|
||||
if ((attachmentId == null) || (attachmentId === '') || (toolType.DisplayHeaderAttachment == null) || (toolType.DisplayHeaderAttachment === '')) {
|
||||
$("#HeaderAttachmentFrame").prop("src", "");
|
||||
} else {
|
||||
$("#HeaderAttachmentFrame").prop("src", attachmentUrlBase + "/header/files/" + attachmentId + "/" + toolType.DisplayHeaderAttachment + "?isArchive=true&date="+dateToUse);
|
||||
$("#HeaderAttachmentFrame").prop("src", attachmentUrlBase + "/header/files/" + attachmentId + "/" + toolType.DisplayHeaderAttachment + "?date=" + dateToUse);
|
||||
}
|
||||
$("#DataAttachmentFrame").prop("src", "");
|
||||
}
|
||||
|
||||
@*function MarkAsReviewed() {
|
||||
|
||||
var toolTypeId = $("#ToolTypeID").text();
|
||||
var headerId = $("#HeaderId").text();
|
||||
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
url: "@Url.Content("~/api/awaitingdispo/markasreviewed")?tooltypeid=" + toolTypeId + "&headerid=" + headerId,
|
||||
success: function () {
|
||||
},
|
||||
error: function (e, ajaxOptions, ex) {
|
||||
DisplayWSMessage("error", "There was an error marking header as reviewed.", e, ex);
|
||||
$("#ReviewButton").prop("disabled", false);
|
||||
}
|
||||
});
|
||||
}*@
|
||||
function CheckDate() {
|
||||
var date = new Date($("#HeaderDate").text());
|
||||
return date;
|
||||
}
|
||||
|
||||
function LoadDetails() {
|
||||
|
||||
|
||||
|
||||
ShowDetailsDiv();
|
||||
|
||||
LoadHeaderAttachment();
|
||||
var dateToUse = $("#HeaderDate").text();
|
||||
var gridCreated = $("#DetailsGrid").data("igGrid");
|
||||
@ -269,19 +230,12 @@
|
||||
else {
|
||||
var detailsURL = "@Url.Content("~/api/tooltypes/")" + toolTypeID + "/headers/" + headerId + "/data";
|
||||
}
|
||||
//Changed from here
|
||||
//if (CheckArchive() == true) {
|
||||
// detailsURL = detailsURL + "?isArchive=true";
|
||||
//}
|
||||
|
||||
//Changed to here
|
||||
var gridColumns = [
|
||||
{ key: "AttachmentID", dataType: "string", hidden: true },
|
||||
{ key: "Title", dataType: "string", hidden: true },
|
||||
];
|
||||
|
||||
for (var i = 0; i < toolTypeMetaData.length; i++)
|
||||
{
|
||||
for (var i = 0; i < toolTypeMetaData.length; i++) {
|
||||
var f = toolTypeMetaData[i];
|
||||
if ((f.Header == false) && (f.GridDisplayOrder > 0)) {
|
||||
var col = {
|
||||
@ -294,7 +248,7 @@
|
||||
if (col.formatter != null) {
|
||||
if (col.formatter == "boolToYesNo")
|
||||
col.formatter = boolToYesNo;
|
||||
else
|
||||
else
|
||||
col.formatter = null;
|
||||
}
|
||||
gridColumns.push(col);
|
||||
@ -312,9 +266,7 @@
|
||||
],
|
||||
columns: gridColumns,
|
||||
dataSource: detailsURL,
|
||||
responseDataKey: "Results",
|
||||
//dataBound: MarkAsReviewed,
|
||||
|
||||
responseDataKey: "Results"
|
||||
};
|
||||
|
||||
if ((toolType != null) && (toolType.DataGridAttributes != null)) {
|
||||
@ -329,8 +281,7 @@
|
||||
|
||||
|
||||
|
||||
function RequestHeaderData()
|
||||
{
|
||||
function RequestHeaderData() {
|
||||
var startDate = $("#StartDate").igDatePicker("value");
|
||||
var startTime = $("#StartTime").igTimePicker("value");
|
||||
|
||||
@ -350,7 +301,6 @@
|
||||
if (initialHeaderId > 0) {
|
||||
headerId = initialHeaderId;
|
||||
parms.headerid = headerId;
|
||||
//isArchive = CheckArchive()
|
||||
$("#HeaderId").text(headerId);
|
||||
$("#HeaderAttachmentId").text(initialHeaderAttachmentId);
|
||||
initialHeaderId = -1;
|
||||
@ -358,18 +308,13 @@
|
||||
|
||||
var headerURL = "@Url.Content("~/api/tooltypes/")" + toolType.ID + "/headers?" + $.param(parms);
|
||||
|
||||
//if (CheckArchive() == true) {
|
||||
// headerURL = headerURL + "&isArchive=true";
|
||||
//}
|
||||
|
||||
var gridColumns = [
|
||||
{ key: "ID", dataType: "number", hidden: true },
|
||||
{ key: "AttachmentID", dataType: "string", hidden: true },
|
||||
{ key: "Title", dataType: "string", hidden: true },
|
||||
];
|
||||
|
||||
for (var i = 0; i < toolTypeMetaData.length; i++)
|
||||
{
|
||||
for (var i = 0; i < toolTypeMetaData.length; i++) {
|
||||
var f = toolTypeMetaData[i];
|
||||
if ((f.Header == true) && (f.GridDisplayOrder > 0)) {
|
||||
var col = {
|
||||
@ -395,11 +340,11 @@
|
||||
height: "100%",
|
||||
width: "100%",
|
||||
features: [
|
||||
{ name: "Paging", type: "local", recordCountKey: "TotalRows", pageSize: 100, pageSizeList : [50, 100, 250, 500], pageSizeUrlKey: "pageSize", "pageIndexUrlKey": "page" },
|
||||
{ name: "Paging", type: "local", recordCountKey: "TotalRows", pageSize: 100, pageSizeList: [50, 100, 250, 500], pageSizeUrlKey: "pageSize", "pageIndexUrlKey": "page" },
|
||||
{ name: "Selection", mode: "row", rowSelectionChanged: HeaderSelectionChanged },
|
||||
{ name: "Filtering", type: "local" },
|
||||
{ name: 'Resizing' },
|
||||
{ name: "Sorting", type:"local"}
|
||||
{ name: "Sorting", type: "local" }
|
||||
],
|
||||
columns: gridColumns,
|
||||
dataSource: headerURL,
|
||||
@ -427,7 +372,7 @@
|
||||
type: "POST",
|
||||
url: "@Url.Content("~/api/awaitingdispo/markasawaiting")?tooltypeid=" + toolTypeId + "&headerid=" + headerId,
|
||||
success: function (e) {
|
||||
DisplayWSMessage("info", "Marked as awaiting disposition",e);
|
||||
DisplayWSMessage("info", "Marked as awaiting disposition", e);
|
||||
$("#ReviewButton").prop("disabled", false);
|
||||
},
|
||||
error: function (e, ajaxOptions, ex) {
|
||||
@ -463,7 +408,7 @@
|
||||
|
||||
$("#StartDate").igDatePicker({
|
||||
dateInputFormat: "date",
|
||||
value: startTime,
|
||||
value: startTime,
|
||||
width: 125
|
||||
});
|
||||
|
||||
@ -487,13 +432,7 @@
|
||||
width: 110
|
||||
});
|
||||
}
|
||||
//function CheckArchive() {
|
||||
// var isArchive = new Boolean(false);
|
||||
|
||||
// isArchive = document.getElementById("isArchive").checked;
|
||||
|
||||
// return isArchive;
|
||||
//}
|
||||
$(document).ready(function () {
|
||||
|
||||
$("#ToolType").igCombo({
|
||||
@ -507,7 +446,7 @@
|
||||
LoadHeaderGrid();
|
||||
},
|
||||
selectionChanged: LoadHeaderGrid,
|
||||
initialSelectedItems: [ { value: @Model.ToolTypeID } ]
|
||||
initialSelectedItems: [{ value: @Model.ToolTypeID }]
|
||||
});
|
||||
|
||||
SetInitialDateTimes();
|
||||
@ -522,13 +461,6 @@
|
||||
|
||||
$("#OIExportButton").click(OIExportButton);
|
||||
|
||||
//setInterval(function () {
|
||||
// if ($("#chkAutoRefresh").is(':checked')) {
|
||||
// SetInitialDateTimes();
|
||||
// $("#LoadHeadersButton").click();
|
||||
// }
|
||||
// }, 180000);
|
||||
|
||||
});
|
||||
|
||||
</script>
|
@ -1,5 +1,6 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width" />
|
||||
@ -8,7 +9,8 @@
|
||||
<script src="~/js/modernizr-3.6.0-custom.js" type="text/javascript" asp-append-version="true"></script>
|
||||
|
||||
<link href="~/styles/bootstrap.min.css" rel="stylesheet" asp-append-version="true" />
|
||||
<link href="~/igniteui/css/themes/bootstrap3/default/infragistics.theme.css" rel="stylesheet" asp-append-version="true" />
|
||||
<link href="~/igniteui/css/themes/bootstrap3/default/infragistics.theme.css" rel="stylesheet"
|
||||
asp-append-version="true" />
|
||||
<link href="~/igniteui/css/structure/infragistics.css" rel="stylesheet" asp-append-version="true" />
|
||||
<link href="~/styles/site.css" rel="stylesheet" asp-append-version="true" />
|
||||
|
||||
@ -32,6 +34,7 @@
|
||||
});
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
@{
|
||||
bool isTestDatabase = false;
|
||||
@ -40,7 +43,6 @@
|
||||
{
|
||||
Boolean.TryParse(Convert.ToString(testDatabaseValue), out isTestDatabase);
|
||||
}
|
||||
|
||||
}
|
||||
<div class="navbar navbar-fixed-top @(isTestDatabase ? "test-database" : "" )">
|
||||
<div class="container-fluid">
|
||||
@ -88,5 +90,5 @@
|
||||
<script src="~/js/respond.min.js" type="text/javascript" asp-append-version="true"></script>
|
||||
@RenderSection("scripts", required: false)
|
||||
</body>
|
||||
</html>
|
||||
|
||||
</html>
|
||||
|
@ -6,11 +6,7 @@
|
||||
"AttachmentPath": "\\\\messv02ecc1.ec.local\\EC_Metrology_Si\\MetrologyAttachments",
|
||||
"BuildNumber": "1",
|
||||
"Company": "Infineon Technologies Americas Corp.",
|
||||
"ConnectionStrings": {
|
||||
"SQL": "Data Source=messv01ec.ec.local\\PROD1,53959;Integrated Security=True;Initial Catalog=Metrology_Archive;",
|
||||
"SQL2": "Data Source=messv01ec.ec.local\\PROD1,53959;Integrated Security=True;Initial Catalog=Metrology_Archive;",
|
||||
"SQL3": "\"Server=.\\\\messv01ec.ec.local\\PROD1,53959;Database=Metrology_Archive;User Id=sa;Password=2BeChanged!;\";"
|
||||
},
|
||||
"ConnectionString": "Data Source=messv01ec.ec.local\\PROD1,53959;Integrated Security=True;Initial Catalog=Metrology_Archive;",
|
||||
"GitCommitSeven": "1234567",
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
@ -21,7 +17,7 @@
|
||||
}
|
||||
},
|
||||
"InboundApiAllowedIPList": "",
|
||||
"OIExportPath": "\\\\openinsight-db-srv.na.infineon.com\\apps\\Metrology\\NewSiteData",
|
||||
"OIExportPath": "\\\\openinsight-db-srv.na.infineon.com\\apps\\Metrology\\Data",
|
||||
"Serilog": {
|
||||
"Using": [
|
||||
"Serilog.Sinks.Console",
|
||||
|
@ -6,11 +6,7 @@
|
||||
"AttachmentPath": "\\\\messv02ecc1.ec.local\\EC_Metrology_Si\\MetrologyAttachments",
|
||||
"BuildNumber": "1",
|
||||
"Company": "Infineon Technologies Americas Corp.",
|
||||
"ConnectionStrings": {
|
||||
"SQL": "Data Source=messv01ec.ec.local\\PROD1,53959;Integrated Security=True;Initial Catalog=Metrology_Archive;",
|
||||
"SQL2": "Data Source=messv01ec.ec.local\\PROD1,53959;Integrated Security=True;Initial Catalog=Metrology_Archive;",
|
||||
"SQL3": "\"Server=.\\\\messv01ec.ec.local\\PROD1,53959;Database=Metrology_Archive;User Id=sa;Password=2BeChanged!;\";"
|
||||
},
|
||||
"ConnectionString": "Data Source=messv01ec.ec.local\\PROD1,53959;Integrated Security=True;Initial Catalog=Metrology_Archive;",
|
||||
"GitCommitSeven": "1234567",
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
@ -21,7 +17,7 @@
|
||||
}
|
||||
},
|
||||
"InboundApiAllowedIPList": "",
|
||||
"OIExportPath": "\\\\openinsight-db-srv.na.infineon.com\\apps\\Metrology\\NewSiteData",
|
||||
"OIExportPath": "\\\\openinsight-db-srv.na.infineon.com\\apps\\Metrology\\Data",
|
||||
"Serilog": {
|
||||
"Using": [
|
||||
"Serilog.Sinks.Console",
|
||||
@ -59,6 +55,6 @@
|
||||
"Application": "Sample"
|
||||
}
|
||||
},
|
||||
"URLs": "https://localhost:7130;http://localhost:5126",
|
||||
"URLs": "http://localhost:5002;",
|
||||
"WorkingDirectoryName": "IFXApps"
|
||||
}
|
@ -1,66 +0,0 @@
|
||||
{
|
||||
"version": "1.0",
|
||||
"defaultProvider": "filesystem",
|
||||
"libraries": [
|
||||
{
|
||||
"provider": "filesystem",
|
||||
"library": "D:/cdnjs/bootstrap@5.1.3/css",
|
||||
"destination": "wwwroot/lib/bootstrap/css"
|
||||
},
|
||||
{
|
||||
"provider": "filesystem",
|
||||
"library": "D:/cdnjs/bootstrap@5.1.3/js",
|
||||
"destination": "wwwroot/lib/bootstrap/js"
|
||||
},
|
||||
{
|
||||
"provider": "filesystem",
|
||||
"library": "D:/cdnjs/bootstrap@5.1.3/scss",
|
||||
"destination": "wwwroot/lib/bootstrap/scss"
|
||||
},
|
||||
{
|
||||
"provider": "filesystem",
|
||||
"library": "D:/cdnjs/bootstrap@5.1.3/scss/forms",
|
||||
"destination": "wwwroot/lib/bootstrap/scss/forms"
|
||||
},
|
||||
{
|
||||
"provider": "filesystem",
|
||||
"library": "D:/cdnjs/bootstrap@5.1.3/scss/helpers",
|
||||
"destination": "wwwroot/lib/bootstrap/scss/helpers"
|
||||
},
|
||||
{
|
||||
"provider": "filesystem",
|
||||
"library": "D:/cdnjs/bootstrap@5.1.3/scss/mixins",
|
||||
"destination": "wwwroot/lib/bootstrap/scss/mixins"
|
||||
},
|
||||
{
|
||||
"provider": "filesystem",
|
||||
"library": "D:/cdnjs/bootstrap@5.1.3/scss/utilities",
|
||||
"destination": "wwwroot/lib/bootstrap/scss/utilities"
|
||||
},
|
||||
{
|
||||
"provider": "filesystem",
|
||||
"library": "D:/cdnjs/bootstrap@5.1.3/scss/vendor",
|
||||
"destination": "wwwroot/lib/bootstrap/scss/vendor"
|
||||
},
|
||||
{
|
||||
"provider": "filesystem",
|
||||
"library": "D:/cdnjs/jquery@3.6.0/",
|
||||
"destination": "wwwroot/lib/jquery/"
|
||||
},
|
||||
{
|
||||
"provider": "filesystem",
|
||||
"library": "D:/cdnjs/jqueryui@1.12.1/",
|
||||
"destination": "wwwroot/lib/jquery-ui/"
|
||||
},
|
||||
{
|
||||
"provider": "filesystem",
|
||||
"library": "D:/cdnjs/jqueryui@1.12.1/images",
|
||||
"destination": "wwwroot/lib/jquery-ui/images"
|
||||
},
|
||||
{
|
||||
"provider": "filesystem",
|
||||
"library": "D:/cdnjs/jqueryui@1.12.1/themes",
|
||||
"destination": "wwwroot/lib/jquery-ui/themes"
|
||||
}
|
||||
]
|
||||
}
|
@ -1,18 +0,0 @@
|
||||
{
|
||||
"version": "1.0",
|
||||
"defaultProvider": "cdnjs",
|
||||
"libraries": [
|
||||
{
|
||||
"library": "jquery@3.6.0",
|
||||
"destination": "wwwroot/lib/jquery/"
|
||||
},
|
||||
{
|
||||
"library": "jqueryui@1.12.1",
|
||||
"destination": "wwwroot/lib/jquery-ui/"
|
||||
},
|
||||
{
|
||||
"library": "bootstrap@5.1.3",
|
||||
"destination": "wwwroot/lib/bootstrap/"
|
||||
}
|
||||
]
|
||||
}
|
5051
Archive/wwwroot/lib/bootstrap/css/bootstrap-grid.css
vendored
5051
Archive/wwwroot/lib/bootstrap/css/bootstrap-grid.css
vendored
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
5050
Archive/wwwroot/lib/bootstrap/css/bootstrap-grid.rtl.css
vendored
5050
Archive/wwwroot/lib/bootstrap/css/bootstrap-grid.rtl.css
vendored
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -1,485 +0,0 @@
|
||||
/*!
|
||||
* Bootstrap Reboot v5.1.3 (https://getbootstrap.com/)
|
||||
* Copyright 2011-2021 The Bootstrap Authors
|
||||
* Copyright 2011-2021 Twitter, Inc.
|
||||
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
|
||||
* Forked from Normalize.css, licensed MIT (https://github.com/necolas/normalize.css/blob/master/LICENSE.md)
|
||||
*/
|
||||
:root {
|
||||
--bs-blue: #0d6efd;
|
||||
--bs-indigo: #6610f2;
|
||||
--bs-purple: #6f42c1;
|
||||
--bs-pink: #d63384;
|
||||
--bs-red: #dc3545;
|
||||
--bs-orange: #fd7e14;
|
||||
--bs-yellow: #ffc107;
|
||||
--bs-green: #198754;
|
||||
--bs-teal: #20c997;
|
||||
--bs-cyan: #0dcaf0;
|
||||
--bs-white: #fff;
|
||||
--bs-gray: #6c757d;
|
||||
--bs-gray-dark: #343a40;
|
||||
--bs-gray-100: #f8f9fa;
|
||||
--bs-gray-200: #e9ecef;
|
||||
--bs-gray-300: #dee2e6;
|
||||
--bs-gray-400: #ced4da;
|
||||
--bs-gray-500: #adb5bd;
|
||||
--bs-gray-600: #6c757d;
|
||||
--bs-gray-700: #495057;
|
||||
--bs-gray-800: #343a40;
|
||||
--bs-gray-900: #212529;
|
||||
--bs-primary: #0d6efd;
|
||||
--bs-secondary: #6c757d;
|
||||
--bs-success: #198754;
|
||||
--bs-info: #0dcaf0;
|
||||
--bs-warning: #ffc107;
|
||||
--bs-danger: #dc3545;
|
||||
--bs-light: #f8f9fa;
|
||||
--bs-dark: #212529;
|
||||
--bs-primary-rgb: 13, 110, 253;
|
||||
--bs-secondary-rgb: 108, 117, 125;
|
||||
--bs-success-rgb: 25, 135, 84;
|
||||
--bs-info-rgb: 13, 202, 240;
|
||||
--bs-warning-rgb: 255, 193, 7;
|
||||
--bs-danger-rgb: 220, 53, 69;
|
||||
--bs-light-rgb: 248, 249, 250;
|
||||
--bs-dark-rgb: 33, 37, 41;
|
||||
--bs-white-rgb: 255, 255, 255;
|
||||
--bs-black-rgb: 0, 0, 0;
|
||||
--bs-body-color-rgb: 33, 37, 41;
|
||||
--bs-body-bg-rgb: 255, 255, 255;
|
||||
--bs-font-sans-serif: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", "Liberation Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
|
||||
--bs-font-monospace: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
|
||||
--bs-gradient: linear-gradient(180deg, rgba(255, 255, 255, 0.15), rgba(255, 255, 255, 0));
|
||||
--bs-body-font-family: var(--bs-font-sans-serif);
|
||||
--bs-body-font-size: 1rem;
|
||||
--bs-body-font-weight: 400;
|
||||
--bs-body-line-height: 1.5;
|
||||
--bs-body-color: #212529;
|
||||
--bs-body-bg: #fff;
|
||||
}
|
||||
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
@media (prefers-reduced-motion: no-preference) {
|
||||
:root {
|
||||
scroll-behavior: smooth;
|
||||
}
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
font-family: var(--bs-body-font-family);
|
||||
font-size: var(--bs-body-font-size);
|
||||
font-weight: var(--bs-body-font-weight);
|
||||
line-height: var(--bs-body-line-height);
|
||||
color: var(--bs-body-color);
|
||||
text-align: var(--bs-body-text-align);
|
||||
background-color: var(--bs-body-bg);
|
||||
-webkit-text-size-adjust: 100%;
|
||||
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
hr {
|
||||
margin: 1rem 0;
|
||||
color: inherit;
|
||||
background-color: currentColor;
|
||||
border: 0;
|
||||
opacity: 0.25;
|
||||
}
|
||||
|
||||
hr:not([size]) {
|
||||
height: 1px;
|
||||
}
|
||||
|
||||
h6, h5, h4, h3, h2, h1 {
|
||||
margin-top: 0;
|
||||
margin-bottom: 0.5rem;
|
||||
font-weight: 500;
|
||||
line-height: 1.2;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: calc(1.375rem + 1.5vw);
|
||||
}
|
||||
@media (min-width: 1200px) {
|
||||
h1 {
|
||||
font-size: 2.5rem;
|
||||
}
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: calc(1.325rem + 0.9vw);
|
||||
}
|
||||
@media (min-width: 1200px) {
|
||||
h2 {
|
||||
font-size: 2rem;
|
||||
}
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-size: calc(1.3rem + 0.6vw);
|
||||
}
|
||||
@media (min-width: 1200px) {
|
||||
h3 {
|
||||
font-size: 1.75rem;
|
||||
}
|
||||
}
|
||||
|
||||
h4 {
|
||||
font-size: calc(1.275rem + 0.3vw);
|
||||
}
|
||||
@media (min-width: 1200px) {
|
||||
h4 {
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
}
|
||||
|
||||
h5 {
|
||||
font-size: 1.25rem;
|
||||
}
|
||||
|
||||
h6 {
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
p {
|
||||
margin-top: 0;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
abbr[title],
|
||||
abbr[data-bs-original-title] {
|
||||
-webkit-text-decoration: underline dotted;
|
||||
text-decoration: underline dotted;
|
||||
cursor: help;
|
||||
-webkit-text-decoration-skip-ink: none;
|
||||
text-decoration-skip-ink: none;
|
||||
}
|
||||
|
||||
address {
|
||||
margin-bottom: 1rem;
|
||||
font-style: normal;
|
||||
line-height: inherit;
|
||||
}
|
||||
|
||||
ol,
|
||||
ul {
|
||||
padding-left: 2rem;
|
||||
}
|
||||
|
||||
ol,
|
||||
ul,
|
||||
dl {
|
||||
margin-top: 0;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
ol ol,
|
||||
ul ul,
|
||||
ol ul,
|
||||
ul ol {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
dt {
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
dd {
|
||||
margin-bottom: 0.5rem;
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
blockquote {
|
||||
margin: 0 0 1rem;
|
||||
}
|
||||
|
||||
b,
|
||||
strong {
|
||||
font-weight: bolder;
|
||||
}
|
||||
|
||||
small {
|
||||
font-size: 0.875em;
|
||||
}
|
||||
|
||||
mark {
|
||||
padding: 0.2em;
|
||||
background-color: #fcf8e3;
|
||||
}
|
||||
|
||||
sub,
|
||||
sup {
|
||||
position: relative;
|
||||
font-size: 0.75em;
|
||||
line-height: 0;
|
||||
vertical-align: baseline;
|
||||
}
|
||||
|
||||
sub {
|
||||
bottom: -0.25em;
|
||||
}
|
||||
|
||||
sup {
|
||||
top: -0.5em;
|
||||
}
|
||||
|
||||
a {
|
||||
color: #0d6efd;
|
||||
text-decoration: underline;
|
||||
}
|
||||
a:hover {
|
||||
color: #0a58ca;
|
||||
}
|
||||
|
||||
a:not([href]):not([class]), a:not([href]):not([class]):hover {
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
pre,
|
||||
code,
|
||||
kbd,
|
||||
samp {
|
||||
font-family: var(--bs-font-monospace);
|
||||
font-size: 1em;
|
||||
direction: ltr /* rtl:ignore */;
|
||||
unicode-bidi: bidi-override;
|
||||
}
|
||||
|
||||
pre {
|
||||
display: block;
|
||||
margin-top: 0;
|
||||
margin-bottom: 1rem;
|
||||
overflow: auto;
|
||||
font-size: 0.875em;
|
||||
}
|
||||
pre code {
|
||||
font-size: inherit;
|
||||
color: inherit;
|
||||
word-break: normal;
|
||||
}
|
||||
|
||||
code {
|
||||
font-size: 0.875em;
|
||||
color: #d63384;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
a > code {
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
kbd {
|
||||
padding: 0.2rem 0.4rem;
|
||||
font-size: 0.875em;
|
||||
color: #fff;
|
||||
background-color: #212529;
|
||||
border-radius: 0.2rem;
|
||||
}
|
||||
kbd kbd {
|
||||
padding: 0;
|
||||
font-size: 1em;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
figure {
|
||||
margin: 0 0 1rem;
|
||||
}
|
||||
|
||||
img,
|
||||
svg {
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
table {
|
||||
caption-side: bottom;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
caption {
|
||||
padding-top: 0.5rem;
|
||||
padding-bottom: 0.5rem;
|
||||
color: #6c757d;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
th {
|
||||
text-align: inherit;
|
||||
text-align: -webkit-match-parent;
|
||||
}
|
||||
|
||||
thead,
|
||||
tbody,
|
||||
tfoot,
|
||||
tr,
|
||||
td,
|
||||
th {
|
||||
border-color: inherit;
|
||||
border-style: solid;
|
||||
border-width: 0;
|
||||
}
|
||||
|
||||
label {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
button {
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
button:focus:not(:focus-visible) {
|
||||
outline: 0;
|
||||
}
|
||||
|
||||
input,
|
||||
button,
|
||||
select,
|
||||
optgroup,
|
||||
textarea {
|
||||
margin: 0;
|
||||
font-family: inherit;
|
||||
font-size: inherit;
|
||||
line-height: inherit;
|
||||
}
|
||||
|
||||
button,
|
||||
select {
|
||||
text-transform: none;
|
||||
}
|
||||
|
||||
[role=button] {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
select {
|
||||
word-wrap: normal;
|
||||
}
|
||||
select:disabled {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
[list]::-webkit-calendar-picker-indicator {
|
||||
display: none;
|
||||
}
|
||||
|
||||
button,
|
||||
[type=button],
|
||||
[type=reset],
|
||||
[type=submit] {
|
||||
-webkit-appearance: button;
|
||||
}
|
||||
button:not(:disabled),
|
||||
[type=button]:not(:disabled),
|
||||
[type=reset]:not(:disabled),
|
||||
[type=submit]:not(:disabled) {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
::-moz-focus-inner {
|
||||
padding: 0;
|
||||
border-style: none;
|
||||
}
|
||||
|
||||
textarea {
|
||||
resize: vertical;
|
||||
}
|
||||
|
||||
fieldset {
|
||||
min-width: 0;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
legend {
|
||||
float: left;
|
||||
width: 100%;
|
||||
padding: 0;
|
||||
margin-bottom: 0.5rem;
|
||||
font-size: calc(1.275rem + 0.3vw);
|
||||
line-height: inherit;
|
||||
}
|
||||
@media (min-width: 1200px) {
|
||||
legend {
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
}
|
||||
legend + * {
|
||||
clear: left;
|
||||
}
|
||||
|
||||
::-webkit-datetime-edit-fields-wrapper,
|
||||
::-webkit-datetime-edit-text,
|
||||
::-webkit-datetime-edit-minute,
|
||||
::-webkit-datetime-edit-hour-field,
|
||||
::-webkit-datetime-edit-day-field,
|
||||
::-webkit-datetime-edit-month-field,
|
||||
::-webkit-datetime-edit-year-field {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
::-webkit-inner-spin-button {
|
||||
height: auto;
|
||||
}
|
||||
|
||||
[type=search] {
|
||||
outline-offset: -2px;
|
||||
-webkit-appearance: textfield;
|
||||
}
|
||||
|
||||
/* rtl:raw:
|
||||
[type="tel"],
|
||||
[type="url"],
|
||||
[type="email"],
|
||||
[type="number"] {
|
||||
direction: ltr;
|
||||
}
|
||||
*/
|
||||
::-webkit-search-decoration {
|
||||
-webkit-appearance: none;
|
||||
}
|
||||
|
||||
::-webkit-color-swatch-wrapper {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
::-webkit-file-upload-button {
|
||||
font: inherit;
|
||||
}
|
||||
|
||||
::file-selector-button {
|
||||
font: inherit;
|
||||
}
|
||||
|
||||
::-webkit-file-upload-button {
|
||||
font: inherit;
|
||||
-webkit-appearance: button;
|
||||
}
|
||||
|
||||
output {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
iframe {
|
||||
border: 0;
|
||||
}
|
||||
|
||||
summary {
|
||||
display: list-item;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
progress {
|
||||
vertical-align: baseline;
|
||||
}
|
||||
|
||||
[hidden] {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
/*# sourceMappingURL=bootstrap-reboot.css.map */
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -1,482 +0,0 @@
|
||||
/*!
|
||||
* Bootstrap Reboot v5.1.3 (https://getbootstrap.com/)
|
||||
* Copyright 2011-2021 The Bootstrap Authors
|
||||
* Copyright 2011-2021 Twitter, Inc.
|
||||
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
|
||||
* Forked from Normalize.css, licensed MIT (https://github.com/necolas/normalize.css/blob/master/LICENSE.md)
|
||||
*/
|
||||
:root {
|
||||
--bs-blue: #0d6efd;
|
||||
--bs-indigo: #6610f2;
|
||||
--bs-purple: #6f42c1;
|
||||
--bs-pink: #d63384;
|
||||
--bs-red: #dc3545;
|
||||
--bs-orange: #fd7e14;
|
||||
--bs-yellow: #ffc107;
|
||||
--bs-green: #198754;
|
||||
--bs-teal: #20c997;
|
||||
--bs-cyan: #0dcaf0;
|
||||
--bs-white: #fff;
|
||||
--bs-gray: #6c757d;
|
||||
--bs-gray-dark: #343a40;
|
||||
--bs-gray-100: #f8f9fa;
|
||||
--bs-gray-200: #e9ecef;
|
||||
--bs-gray-300: #dee2e6;
|
||||
--bs-gray-400: #ced4da;
|
||||
--bs-gray-500: #adb5bd;
|
||||
--bs-gray-600: #6c757d;
|
||||
--bs-gray-700: #495057;
|
||||
--bs-gray-800: #343a40;
|
||||
--bs-gray-900: #212529;
|
||||
--bs-primary: #0d6efd;
|
||||
--bs-secondary: #6c757d;
|
||||
--bs-success: #198754;
|
||||
--bs-info: #0dcaf0;
|
||||
--bs-warning: #ffc107;
|
||||
--bs-danger: #dc3545;
|
||||
--bs-light: #f8f9fa;
|
||||
--bs-dark: #212529;
|
||||
--bs-primary-rgb: 13, 110, 253;
|
||||
--bs-secondary-rgb: 108, 117, 125;
|
||||
--bs-success-rgb: 25, 135, 84;
|
||||
--bs-info-rgb: 13, 202, 240;
|
||||
--bs-warning-rgb: 255, 193, 7;
|
||||
--bs-danger-rgb: 220, 53, 69;
|
||||
--bs-light-rgb: 248, 249, 250;
|
||||
--bs-dark-rgb: 33, 37, 41;
|
||||
--bs-white-rgb: 255, 255, 255;
|
||||
--bs-black-rgb: 0, 0, 0;
|
||||
--bs-body-color-rgb: 33, 37, 41;
|
||||
--bs-body-bg-rgb: 255, 255, 255;
|
||||
--bs-font-sans-serif: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", "Liberation Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
|
||||
--bs-font-monospace: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
|
||||
--bs-gradient: linear-gradient(180deg, rgba(255, 255, 255, 0.15), rgba(255, 255, 255, 0));
|
||||
--bs-body-font-family: var(--bs-font-sans-serif);
|
||||
--bs-body-font-size: 1rem;
|
||||
--bs-body-font-weight: 400;
|
||||
--bs-body-line-height: 1.5;
|
||||
--bs-body-color: #212529;
|
||||
--bs-body-bg: #fff;
|
||||
}
|
||||
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
@media (prefers-reduced-motion: no-preference) {
|
||||
:root {
|
||||
scroll-behavior: smooth;
|
||||
}
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
font-family: var(--bs-body-font-family);
|
||||
font-size: var(--bs-body-font-size);
|
||||
font-weight: var(--bs-body-font-weight);
|
||||
line-height: var(--bs-body-line-height);
|
||||
color: var(--bs-body-color);
|
||||
text-align: var(--bs-body-text-align);
|
||||
background-color: var(--bs-body-bg);
|
||||
-webkit-text-size-adjust: 100%;
|
||||
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
hr {
|
||||
margin: 1rem 0;
|
||||
color: inherit;
|
||||
background-color: currentColor;
|
||||
border: 0;
|
||||
opacity: 0.25;
|
||||
}
|
||||
|
||||
hr:not([size]) {
|
||||
height: 1px;
|
||||
}
|
||||
|
||||
h6, h5, h4, h3, h2, h1 {
|
||||
margin-top: 0;
|
||||
margin-bottom: 0.5rem;
|
||||
font-weight: 500;
|
||||
line-height: 1.2;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: calc(1.375rem + 1.5vw);
|
||||
}
|
||||
@media (min-width: 1200px) {
|
||||
h1 {
|
||||
font-size: 2.5rem;
|
||||
}
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: calc(1.325rem + 0.9vw);
|
||||
}
|
||||
@media (min-width: 1200px) {
|
||||
h2 {
|
||||
font-size: 2rem;
|
||||
}
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-size: calc(1.3rem + 0.6vw);
|
||||
}
|
||||
@media (min-width: 1200px) {
|
||||
h3 {
|
||||
font-size: 1.75rem;
|
||||
}
|
||||
}
|
||||
|
||||
h4 {
|
||||
font-size: calc(1.275rem + 0.3vw);
|
||||
}
|
||||
@media (min-width: 1200px) {
|
||||
h4 {
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
}
|
||||
|
||||
h5 {
|
||||
font-size: 1.25rem;
|
||||
}
|
||||
|
||||
h6 {
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
p {
|
||||
margin-top: 0;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
abbr[title],
|
||||
abbr[data-bs-original-title] {
|
||||
-webkit-text-decoration: underline dotted;
|
||||
text-decoration: underline dotted;
|
||||
cursor: help;
|
||||
-webkit-text-decoration-skip-ink: none;
|
||||
text-decoration-skip-ink: none;
|
||||
}
|
||||
|
||||
address {
|
||||
margin-bottom: 1rem;
|
||||
font-style: normal;
|
||||
line-height: inherit;
|
||||
}
|
||||
|
||||
ol,
|
||||
ul {
|
||||
padding-right: 2rem;
|
||||
}
|
||||
|
||||
ol,
|
||||
ul,
|
||||
dl {
|
||||
margin-top: 0;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
ol ol,
|
||||
ul ul,
|
||||
ol ul,
|
||||
ul ol {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
dt {
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
dd {
|
||||
margin-bottom: 0.5rem;
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
blockquote {
|
||||
margin: 0 0 1rem;
|
||||
}
|
||||
|
||||
b,
|
||||
strong {
|
||||
font-weight: bolder;
|
||||
}
|
||||
|
||||
small {
|
||||
font-size: 0.875em;
|
||||
}
|
||||
|
||||
mark {
|
||||
padding: 0.2em;
|
||||
background-color: #fcf8e3;
|
||||
}
|
||||
|
||||
sub,
|
||||
sup {
|
||||
position: relative;
|
||||
font-size: 0.75em;
|
||||
line-height: 0;
|
||||
vertical-align: baseline;
|
||||
}
|
||||
|
||||
sub {
|
||||
bottom: -0.25em;
|
||||
}
|
||||
|
||||
sup {
|
||||
top: -0.5em;
|
||||
}
|
||||
|
||||
a {
|
||||
color: #0d6efd;
|
||||
text-decoration: underline;
|
||||
}
|
||||
a:hover {
|
||||
color: #0a58ca;
|
||||
}
|
||||
|
||||
a:not([href]):not([class]), a:not([href]):not([class]):hover {
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
pre,
|
||||
code,
|
||||
kbd,
|
||||
samp {
|
||||
font-family: var(--bs-font-monospace);
|
||||
font-size: 1em;
|
||||
direction: ltr ;
|
||||
unicode-bidi: bidi-override;
|
||||
}
|
||||
|
||||
pre {
|
||||
display: block;
|
||||
margin-top: 0;
|
||||
margin-bottom: 1rem;
|
||||
overflow: auto;
|
||||
font-size: 0.875em;
|
||||
}
|
||||
pre code {
|
||||
font-size: inherit;
|
||||
color: inherit;
|
||||
word-break: normal;
|
||||
}
|
||||
|
||||
code {
|
||||
font-size: 0.875em;
|
||||
color: #d63384;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
a > code {
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
kbd {
|
||||
padding: 0.2rem 0.4rem;
|
||||
font-size: 0.875em;
|
||||
color: #fff;
|
||||
background-color: #212529;
|
||||
border-radius: 0.2rem;
|
||||
}
|
||||
kbd kbd {
|
||||
padding: 0;
|
||||
font-size: 1em;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
figure {
|
||||
margin: 0 0 1rem;
|
||||
}
|
||||
|
||||
img,
|
||||
svg {
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
table {
|
||||
caption-side: bottom;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
caption {
|
||||
padding-top: 0.5rem;
|
||||
padding-bottom: 0.5rem;
|
||||
color: #6c757d;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
th {
|
||||
text-align: inherit;
|
||||
text-align: -webkit-match-parent;
|
||||
}
|
||||
|
||||
thead,
|
||||
tbody,
|
||||
tfoot,
|
||||
tr,
|
||||
td,
|
||||
th {
|
||||
border-color: inherit;
|
||||
border-style: solid;
|
||||
border-width: 0;
|
||||
}
|
||||
|
||||
label {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
button {
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
button:focus:not(:focus-visible) {
|
||||
outline: 0;
|
||||
}
|
||||
|
||||
input,
|
||||
button,
|
||||
select,
|
||||
optgroup,
|
||||
textarea {
|
||||
margin: 0;
|
||||
font-family: inherit;
|
||||
font-size: inherit;
|
||||
line-height: inherit;
|
||||
}
|
||||
|
||||
button,
|
||||
select {
|
||||
text-transform: none;
|
||||
}
|
||||
|
||||
[role=button] {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
select {
|
||||
word-wrap: normal;
|
||||
}
|
||||
select:disabled {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
[list]::-webkit-calendar-picker-indicator {
|
||||
display: none;
|
||||
}
|
||||
|
||||
button,
|
||||
[type=button],
|
||||
[type=reset],
|
||||
[type=submit] {
|
||||
-webkit-appearance: button;
|
||||
}
|
||||
button:not(:disabled),
|
||||
[type=button]:not(:disabled),
|
||||
[type=reset]:not(:disabled),
|
||||
[type=submit]:not(:disabled) {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
::-moz-focus-inner {
|
||||
padding: 0;
|
||||
border-style: none;
|
||||
}
|
||||
|
||||
textarea {
|
||||
resize: vertical;
|
||||
}
|
||||
|
||||
fieldset {
|
||||
min-width: 0;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
legend {
|
||||
float: right;
|
||||
width: 100%;
|
||||
padding: 0;
|
||||
margin-bottom: 0.5rem;
|
||||
font-size: calc(1.275rem + 0.3vw);
|
||||
line-height: inherit;
|
||||
}
|
||||
@media (min-width: 1200px) {
|
||||
legend {
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
}
|
||||
legend + * {
|
||||
clear: right;
|
||||
}
|
||||
|
||||
::-webkit-datetime-edit-fields-wrapper,
|
||||
::-webkit-datetime-edit-text,
|
||||
::-webkit-datetime-edit-minute,
|
||||
::-webkit-datetime-edit-hour-field,
|
||||
::-webkit-datetime-edit-day-field,
|
||||
::-webkit-datetime-edit-month-field,
|
||||
::-webkit-datetime-edit-year-field {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
::-webkit-inner-spin-button {
|
||||
height: auto;
|
||||
}
|
||||
|
||||
[type=search] {
|
||||
outline-offset: -2px;
|
||||
-webkit-appearance: textfield;
|
||||
}
|
||||
|
||||
[type="tel"],
|
||||
[type="url"],
|
||||
[type="email"],
|
||||
[type="number"] {
|
||||
direction: ltr;
|
||||
}
|
||||
::-webkit-search-decoration {
|
||||
-webkit-appearance: none;
|
||||
}
|
||||
|
||||
::-webkit-color-swatch-wrapper {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
::-webkit-file-upload-button {
|
||||
font: inherit;
|
||||
}
|
||||
|
||||
::file-selector-button {
|
||||
font: inherit;
|
||||
}
|
||||
|
||||
::-webkit-file-upload-button {
|
||||
font: inherit;
|
||||
-webkit-appearance: button;
|
||||
}
|
||||
|
||||
output {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
iframe {
|
||||
border: 0;
|
||||
}
|
||||
|
||||
summary {
|
||||
display: list-item;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
progress {
|
||||
vertical-align: baseline;
|
||||
}
|
||||
|
||||
[hidden] {
|
||||
display: none !important;
|
||||
}
|
||||
/*# sourceMappingURL=bootstrap-reboot.rtl.css.map */
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
11266
Archive/wwwroot/lib/bootstrap/css/bootstrap.css
vendored
11266
Archive/wwwroot/lib/bootstrap/css/bootstrap.css
vendored
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
11242
Archive/wwwroot/lib/bootstrap/css/bootstrap.rtl.css
vendored
11242
Archive/wwwroot/lib/bootstrap/css/bootstrap.rtl.css
vendored
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
6812
Archive/wwwroot/lib/bootstrap/js/bootstrap.bundle.js
vendored
6812
Archive/wwwroot/lib/bootstrap/js/bootstrap.bundle.js
vendored
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
4999
Archive/wwwroot/lib/bootstrap/js/bootstrap.esm.js
vendored
4999
Archive/wwwroot/lib/bootstrap/js/bootstrap.esm.js
vendored
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
5046
Archive/wwwroot/lib/bootstrap/js/bootstrap.js
vendored
5046
Archive/wwwroot/lib/bootstrap/js/bootstrap.js
vendored
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -1,118 +0,0 @@
|
||||
//
|
||||
// Base styles
|
||||
//
|
||||
|
||||
.accordion-button {
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
padding: $accordion-button-padding-y $accordion-button-padding-x;
|
||||
@include font-size($font-size-base);
|
||||
color: $accordion-button-color;
|
||||
text-align: left; // Reset button style
|
||||
background-color: $accordion-button-bg;
|
||||
border: 0;
|
||||
@include border-radius(0);
|
||||
overflow-anchor: none;
|
||||
@include transition($accordion-transition);
|
||||
|
||||
&:not(.collapsed) {
|
||||
color: $accordion-button-active-color;
|
||||
background-color: $accordion-button-active-bg;
|
||||
box-shadow: inset 0 ($accordion-border-width * -1) 0 $accordion-border-color;
|
||||
|
||||
&::after {
|
||||
background-image: escape-svg($accordion-button-active-icon);
|
||||
transform: $accordion-icon-transform;
|
||||
}
|
||||
}
|
||||
|
||||
// Accordion icon
|
||||
&::after {
|
||||
flex-shrink: 0;
|
||||
width: $accordion-icon-width;
|
||||
height: $accordion-icon-width;
|
||||
margin-left: auto;
|
||||
content: "";
|
||||
background-image: escape-svg($accordion-button-icon);
|
||||
background-repeat: no-repeat;
|
||||
background-size: $accordion-icon-width;
|
||||
@include transition($accordion-icon-transition);
|
||||
}
|
||||
|
||||
&:hover {
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
&:focus {
|
||||
z-index: 3;
|
||||
border-color: $accordion-button-focus-border-color;
|
||||
outline: 0;
|
||||
box-shadow: $accordion-button-focus-box-shadow;
|
||||
}
|
||||
}
|
||||
|
||||
.accordion-header {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.accordion-item {
|
||||
background-color: $accordion-bg;
|
||||
border: $accordion-border-width solid $accordion-border-color;
|
||||
|
||||
&:first-of-type {
|
||||
@include border-top-radius($accordion-border-radius);
|
||||
|
||||
.accordion-button {
|
||||
@include border-top-radius($accordion-inner-border-radius);
|
||||
}
|
||||
}
|
||||
|
||||
&:not(:first-of-type) {
|
||||
border-top: 0;
|
||||
}
|
||||
|
||||
// Only set a border-radius on the last item if the accordion is collapsed
|
||||
&:last-of-type {
|
||||
@include border-bottom-radius($accordion-border-radius);
|
||||
|
||||
.accordion-button {
|
||||
&.collapsed {
|
||||
@include border-bottom-radius($accordion-inner-border-radius);
|
||||
}
|
||||
}
|
||||
|
||||
.accordion-collapse {
|
||||
@include border-bottom-radius($accordion-border-radius);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.accordion-body {
|
||||
padding: $accordion-body-padding-y $accordion-body-padding-x;
|
||||
}
|
||||
|
||||
|
||||
// Flush accordion items
|
||||
//
|
||||
// Remove borders and border-radius to keep accordion items edge-to-edge.
|
||||
|
||||
.accordion-flush {
|
||||
.accordion-collapse {
|
||||
border-width: 0;
|
||||
}
|
||||
|
||||
.accordion-item {
|
||||
border-right: 0;
|
||||
border-left: 0;
|
||||
@include border-radius(0);
|
||||
|
||||
&:first-child { border-top: 0; }
|
||||
&:last-child { border-bottom: 0; }
|
||||
|
||||
.accordion-button {
|
||||
@include border-radius(0);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,57 +0,0 @@
|
||||
//
|
||||
// Base styles
|
||||
//
|
||||
|
||||
.alert {
|
||||
position: relative;
|
||||
padding: $alert-padding-y $alert-padding-x;
|
||||
margin-bottom: $alert-margin-bottom;
|
||||
border: $alert-border-width solid transparent;
|
||||
@include border-radius($alert-border-radius);
|
||||
}
|
||||
|
||||
// Headings for larger alerts
|
||||
.alert-heading {
|
||||
// Specified to prevent conflicts of changing $headings-color
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
// Provide class for links that match alerts
|
||||
.alert-link {
|
||||
font-weight: $alert-link-font-weight;
|
||||
}
|
||||
|
||||
|
||||
// Dismissible alerts
|
||||
//
|
||||
// Expand the right padding and account for the close button's positioning.
|
||||
|
||||
.alert-dismissible {
|
||||
padding-right: $alert-dismissible-padding-r;
|
||||
|
||||
// Adjust close link position
|
||||
.btn-close {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
z-index: $stretched-link-z-index + 1;
|
||||
padding: $alert-padding-y * 1.25 $alert-padding-x;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// scss-docs-start alert-modifiers
|
||||
// Generate contextual modifier classes for colorizing the alert.
|
||||
|
||||
@each $state, $value in $theme-colors {
|
||||
$alert-background: shift-color($value, $alert-bg-scale);
|
||||
$alert-border: shift-color($value, $alert-border-scale);
|
||||
$alert-color: shift-color($value, $alert-color-scale);
|
||||
@if (contrast-ratio($alert-background, $alert-color) < $min-contrast-ratio) {
|
||||
$alert-color: mix($value, color-contrast($alert-background), abs($alert-color-scale));
|
||||
}
|
||||
.alert-#{$state} {
|
||||
@include alert-variant($alert-background, $alert-border, $alert-color);
|
||||
}
|
||||
}
|
||||
// scss-docs-end alert-modifiers
|
@ -1,29 +0,0 @@
|
||||
// Base class
|
||||
//
|
||||
// Requires one of the contextual, color modifier classes for `color` and
|
||||
// `background-color`.
|
||||
|
||||
.badge {
|
||||
display: inline-block;
|
||||
padding: $badge-padding-y $badge-padding-x;
|
||||
@include font-size($badge-font-size);
|
||||
font-weight: $badge-font-weight;
|
||||
line-height: 1;
|
||||
color: $badge-color;
|
||||
text-align: center;
|
||||
white-space: nowrap;
|
||||
vertical-align: baseline;
|
||||
@include border-radius($badge-border-radius);
|
||||
@include gradient-bg();
|
||||
|
||||
// Empty badges collapse automatically
|
||||
&:empty {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
// Quick fix for badges in buttons
|
||||
.btn .badge {
|
||||
position: relative;
|
||||
top: -1px;
|
||||
}
|
@ -1,28 +0,0 @@
|
||||
.breadcrumb {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
padding: $breadcrumb-padding-y $breadcrumb-padding-x;
|
||||
margin-bottom: $breadcrumb-margin-bottom;
|
||||
@include font-size($breadcrumb-font-size);
|
||||
list-style: none;
|
||||
background-color: $breadcrumb-bg;
|
||||
@include border-radius($breadcrumb-border-radius);
|
||||
}
|
||||
|
||||
.breadcrumb-item {
|
||||
// The separator between breadcrumbs (by default, a forward-slash: "/")
|
||||
+ .breadcrumb-item {
|
||||
padding-left: $breadcrumb-item-padding-x;
|
||||
|
||||
&::before {
|
||||
float: left; // Suppress inline spacings and underlining of the separator
|
||||
padding-right: $breadcrumb-item-padding-x;
|
||||
color: $breadcrumb-divider-color;
|
||||
content: var(--#{$variable-prefix}breadcrumb-divider, escape-svg($breadcrumb-divider)) #{"/* rtl:"} var(--#{$variable-prefix}breadcrumb-divider, escape-svg($breadcrumb-divider-flipped)) #{"*/"};
|
||||
}
|
||||
}
|
||||
|
||||
&.active {
|
||||
color: $breadcrumb-active-color;
|
||||
}
|
||||
}
|
@ -1,139 +0,0 @@
|
||||
// Make the div behave like a button
|
||||
.btn-group,
|
||||
.btn-group-vertical {
|
||||
position: relative;
|
||||
display: inline-flex;
|
||||
vertical-align: middle; // match .btn alignment given font-size hack above
|
||||
|
||||
> .btn {
|
||||
position: relative;
|
||||
flex: 1 1 auto;
|
||||
}
|
||||
|
||||
// Bring the hover, focused, and "active" buttons to the front to overlay
|
||||
// the borders properly
|
||||
> .btn-check:checked + .btn,
|
||||
> .btn-check:focus + .btn,
|
||||
> .btn:hover,
|
||||
> .btn:focus,
|
||||
> .btn:active,
|
||||
> .btn.active {
|
||||
z-index: 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Optional: Group multiple button groups together for a toolbar
|
||||
.btn-toolbar {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: flex-start;
|
||||
|
||||
.input-group {
|
||||
width: auto;
|
||||
}
|
||||
}
|
||||
|
||||
.btn-group {
|
||||
// Prevent double borders when buttons are next to each other
|
||||
> .btn:not(:first-child),
|
||||
> .btn-group:not(:first-child) {
|
||||
margin-left: -$btn-border-width;
|
||||
}
|
||||
|
||||
// Reset rounded corners
|
||||
> .btn:not(:last-child):not(.dropdown-toggle),
|
||||
> .btn-group:not(:last-child) > .btn {
|
||||
@include border-end-radius(0);
|
||||
}
|
||||
|
||||
// The left radius should be 0 if the button is:
|
||||
// - the "third or more" child
|
||||
// - the second child and the previous element isn't `.btn-check` (making it the first child visually)
|
||||
// - part of a btn-group which isn't the first child
|
||||
> .btn:nth-child(n + 3),
|
||||
> :not(.btn-check) + .btn,
|
||||
> .btn-group:not(:first-child) > .btn {
|
||||
@include border-start-radius(0);
|
||||
}
|
||||
}
|
||||
|
||||
// Sizing
|
||||
//
|
||||
// Remix the default button sizing classes into new ones for easier manipulation.
|
||||
|
||||
.btn-group-sm > .btn { @extend .btn-sm; }
|
||||
.btn-group-lg > .btn { @extend .btn-lg; }
|
||||
|
||||
|
||||
//
|
||||
// Split button dropdowns
|
||||
//
|
||||
|
||||
.dropdown-toggle-split {
|
||||
padding-right: $btn-padding-x * .75;
|
||||
padding-left: $btn-padding-x * .75;
|
||||
|
||||
&::after,
|
||||
.dropup &::after,
|
||||
.dropend &::after {
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
.dropstart &::before {
|
||||
margin-right: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.btn-sm + .dropdown-toggle-split {
|
||||
padding-right: $btn-padding-x-sm * .75;
|
||||
padding-left: $btn-padding-x-sm * .75;
|
||||
}
|
||||
|
||||
.btn-lg + .dropdown-toggle-split {
|
||||
padding-right: $btn-padding-x-lg * .75;
|
||||
padding-left: $btn-padding-x-lg * .75;
|
||||
}
|
||||
|
||||
|
||||
// The clickable button for toggling the menu
|
||||
// Set the same inset shadow as the :active state
|
||||
.btn-group.show .dropdown-toggle {
|
||||
@include box-shadow($btn-active-box-shadow);
|
||||
|
||||
// Show no shadow for `.btn-link` since it has no other button styles.
|
||||
&.btn-link {
|
||||
@include box-shadow(none);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Vertical button groups
|
||||
//
|
||||
|
||||
.btn-group-vertical {
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
justify-content: center;
|
||||
|
||||
> .btn,
|
||||
> .btn-group {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
> .btn:not(:first-child),
|
||||
> .btn-group:not(:first-child) {
|
||||
margin-top: -$btn-border-width;
|
||||
}
|
||||
|
||||
// Reset rounded corners
|
||||
> .btn:not(:last-child):not(.dropdown-toggle),
|
||||
> .btn-group:not(:last-child) > .btn {
|
||||
@include border-bottom-radius(0);
|
||||
}
|
||||
|
||||
> .btn ~ .btn,
|
||||
> .btn-group:not(:first-child) > .btn {
|
||||
@include border-top-radius(0);
|
||||
}
|
||||
}
|
@ -1,111 +0,0 @@
|
||||
//
|
||||
// Base styles
|
||||
//
|
||||
|
||||
.btn {
|
||||
display: inline-block;
|
||||
font-family: $btn-font-family;
|
||||
font-weight: $btn-font-weight;
|
||||
line-height: $btn-line-height;
|
||||
color: $body-color;
|
||||
text-align: center;
|
||||
text-decoration: if($link-decoration == none, null, none);
|
||||
white-space: $btn-white-space;
|
||||
vertical-align: middle;
|
||||
cursor: if($enable-button-pointers, pointer, null);
|
||||
user-select: none;
|
||||
background-color: transparent;
|
||||
border: $btn-border-width solid transparent;
|
||||
@include button-size($btn-padding-y, $btn-padding-x, $btn-font-size, $btn-border-radius);
|
||||
@include transition($btn-transition);
|
||||
|
||||
&:hover {
|
||||
color: $body-color;
|
||||
text-decoration: if($link-hover-decoration == underline, none, null);
|
||||
}
|
||||
|
||||
.btn-check:focus + &,
|
||||
&:focus {
|
||||
outline: 0;
|
||||
box-shadow: $btn-focus-box-shadow;
|
||||
}
|
||||
|
||||
.btn-check:checked + &,
|
||||
.btn-check:active + &,
|
||||
&:active,
|
||||
&.active {
|
||||
@include box-shadow($btn-active-box-shadow);
|
||||
|
||||
&:focus {
|
||||
@include box-shadow($btn-focus-box-shadow, $btn-active-box-shadow);
|
||||
}
|
||||
}
|
||||
|
||||
&:disabled,
|
||||
&.disabled,
|
||||
fieldset:disabled & {
|
||||
pointer-events: none;
|
||||
opacity: $btn-disabled-opacity;
|
||||
@include box-shadow(none);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Alternate buttons
|
||||
//
|
||||
|
||||
// scss-docs-start btn-variant-loops
|
||||
@each $color, $value in $theme-colors {
|
||||
.btn-#{$color} {
|
||||
@include button-variant($value, $value);
|
||||
}
|
||||
}
|
||||
|
||||
@each $color, $value in $theme-colors {
|
||||
.btn-outline-#{$color} {
|
||||
@include button-outline-variant($value);
|
||||
}
|
||||
}
|
||||
// scss-docs-end btn-variant-loops
|
||||
|
||||
|
||||
//
|
||||
// Link buttons
|
||||
//
|
||||
|
||||
// Make a button look and behave like a link
|
||||
.btn-link {
|
||||
font-weight: $font-weight-normal;
|
||||
color: $btn-link-color;
|
||||
text-decoration: $link-decoration;
|
||||
|
||||
&:hover {
|
||||
color: $btn-link-hover-color;
|
||||
text-decoration: $link-hover-decoration;
|
||||
}
|
||||
|
||||
&:focus {
|
||||
text-decoration: $link-hover-decoration;
|
||||
}
|
||||
|
||||
&:disabled,
|
||||
&.disabled {
|
||||
color: $btn-link-disabled-color;
|
||||
}
|
||||
|
||||
// No need for an active state here
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Button Sizes
|
||||
//
|
||||
|
||||
.btn-lg {
|
||||
@include button-size($btn-padding-y-lg, $btn-padding-x-lg, $btn-font-size-lg, $btn-border-radius-lg);
|
||||
}
|
||||
|
||||
.btn-sm {
|
||||
@include button-size($btn-padding-y-sm, $btn-padding-x-sm, $btn-font-size-sm, $btn-border-radius-sm);
|
||||
}
|
@ -1,216 +0,0 @@
|
||||
//
|
||||
// Base styles
|
||||
//
|
||||
|
||||
.card {
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-width: 0; // See https://github.com/twbs/bootstrap/pull/22740#issuecomment-305868106
|
||||
height: $card-height;
|
||||
word-wrap: break-word;
|
||||
background-color: $card-bg;
|
||||
background-clip: border-box;
|
||||
border: $card-border-width solid $card-border-color;
|
||||
@include border-radius($card-border-radius);
|
||||
@include box-shadow($card-box-shadow);
|
||||
|
||||
> hr {
|
||||
margin-right: 0;
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
> .list-group {
|
||||
border-top: inherit;
|
||||
border-bottom: inherit;
|
||||
|
||||
&:first-child {
|
||||
border-top-width: 0;
|
||||
@include border-top-radius($card-inner-border-radius);
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
border-bottom-width: 0;
|
||||
@include border-bottom-radius($card-inner-border-radius);
|
||||
}
|
||||
}
|
||||
|
||||
// Due to specificity of the above selector (`.card > .list-group`), we must
|
||||
// use a child selector here to prevent double borders.
|
||||
> .card-header + .list-group,
|
||||
> .list-group + .card-footer {
|
||||
border-top: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.card-body {
|
||||
// Enable `flex-grow: 1` for decks and groups so that card blocks take up
|
||||
// as much space as possible, ensuring footers are aligned to the bottom.
|
||||
flex: 1 1 auto;
|
||||
padding: $card-spacer-y $card-spacer-x;
|
||||
color: $card-color;
|
||||
}
|
||||
|
||||
.card-title {
|
||||
margin-bottom: $card-title-spacer-y;
|
||||
}
|
||||
|
||||
.card-subtitle {
|
||||
margin-top: -$card-title-spacer-y * .5;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.card-text:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.card-link {
|
||||
&:hover {
|
||||
text-decoration: if($link-hover-decoration == underline, none, null);
|
||||
}
|
||||
|
||||
+ .card-link {
|
||||
margin-left: $card-spacer-x;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Optional textual caps
|
||||
//
|
||||
|
||||
.card-header {
|
||||
padding: $card-cap-padding-y $card-cap-padding-x;
|
||||
margin-bottom: 0; // Removes the default margin-bottom of <hN>
|
||||
color: $card-cap-color;
|
||||
background-color: $card-cap-bg;
|
||||
border-bottom: $card-border-width solid $card-border-color;
|
||||
|
||||
&:first-child {
|
||||
@include border-radius($card-inner-border-radius $card-inner-border-radius 0 0);
|
||||
}
|
||||
}
|
||||
|
||||
.card-footer {
|
||||
padding: $card-cap-padding-y $card-cap-padding-x;
|
||||
color: $card-cap-color;
|
||||
background-color: $card-cap-bg;
|
||||
border-top: $card-border-width solid $card-border-color;
|
||||
|
||||
&:last-child {
|
||||
@include border-radius(0 0 $card-inner-border-radius $card-inner-border-radius);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Header navs
|
||||
//
|
||||
|
||||
.card-header-tabs {
|
||||
margin-right: -$card-cap-padding-x * .5;
|
||||
margin-bottom: -$card-cap-padding-y;
|
||||
margin-left: -$card-cap-padding-x * .5;
|
||||
border-bottom: 0;
|
||||
|
||||
@if $nav-tabs-link-active-bg != $card-bg {
|
||||
.nav-link.active {
|
||||
background-color: $card-bg;
|
||||
border-bottom-color: $card-bg;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.card-header-pills {
|
||||
margin-right: -$card-cap-padding-x * .5;
|
||||
margin-left: -$card-cap-padding-x * .5;
|
||||
}
|
||||
|
||||
// Card image
|
||||
.card-img-overlay {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
padding: $card-img-overlay-padding;
|
||||
@include border-radius($card-inner-border-radius);
|
||||
}
|
||||
|
||||
.card-img,
|
||||
.card-img-top,
|
||||
.card-img-bottom {
|
||||
width: 100%; // Required because we use flexbox and this inherently applies align-self: stretch
|
||||
}
|
||||
|
||||
.card-img,
|
||||
.card-img-top {
|
||||
@include border-top-radius($card-inner-border-radius);
|
||||
}
|
||||
|
||||
.card-img,
|
||||
.card-img-bottom {
|
||||
@include border-bottom-radius($card-inner-border-radius);
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Card groups
|
||||
//
|
||||
|
||||
.card-group {
|
||||
// The child selector allows nested `.card` within `.card-group`
|
||||
// to display properly.
|
||||
> .card {
|
||||
margin-bottom: $card-group-margin;
|
||||
}
|
||||
|
||||
@include media-breakpoint-up(sm) {
|
||||
display: flex;
|
||||
flex-flow: row wrap;
|
||||
// The child selector allows nested `.card` within `.card-group`
|
||||
// to display properly.
|
||||
> .card {
|
||||
// Flexbugs #4: https://github.com/philipwalton/flexbugs#flexbug-4
|
||||
flex: 1 0 0%;
|
||||
margin-bottom: 0;
|
||||
|
||||
+ .card {
|
||||
margin-left: 0;
|
||||
border-left: 0;
|
||||
}
|
||||
|
||||
// Handle rounded corners
|
||||
@if $enable-rounded {
|
||||
&:not(:last-child) {
|
||||
@include border-end-radius(0);
|
||||
|
||||
.card-img-top,
|
||||
.card-header {
|
||||
// stylelint-disable-next-line property-disallowed-list
|
||||
border-top-right-radius: 0;
|
||||
}
|
||||
.card-img-bottom,
|
||||
.card-footer {
|
||||
// stylelint-disable-next-line property-disallowed-list
|
||||
border-bottom-right-radius: 0;
|
||||
}
|
||||
}
|
||||
|
||||
&:not(:first-child) {
|
||||
@include border-start-radius(0);
|
||||
|
||||
.card-img-top,
|
||||
.card-header {
|
||||
// stylelint-disable-next-line property-disallowed-list
|
||||
border-top-left-radius: 0;
|
||||
}
|
||||
.card-img-bottom,
|
||||
.card-footer {
|
||||
// stylelint-disable-next-line property-disallowed-list
|
||||
border-bottom-left-radius: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,229 +0,0 @@
|
||||
// Notes on the classes:
|
||||
//
|
||||
// 1. .carousel.pointer-event should ideally be pan-y (to allow for users to scroll vertically)
|
||||
// even when their scroll action started on a carousel, but for compatibility (with Firefox)
|
||||
// we're preventing all actions instead
|
||||
// 2. The .carousel-item-start and .carousel-item-end is used to indicate where
|
||||
// the active slide is heading.
|
||||
// 3. .active.carousel-item is the current slide.
|
||||
// 4. .active.carousel-item-start and .active.carousel-item-end is the current
|
||||
// slide in its in-transition state. Only one of these occurs at a time.
|
||||
// 5. .carousel-item-next.carousel-item-start and .carousel-item-prev.carousel-item-end
|
||||
// is the upcoming slide in transition.
|
||||
|
||||
.carousel {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.carousel.pointer-event {
|
||||
touch-action: pan-y;
|
||||
}
|
||||
|
||||
.carousel-inner {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
@include clearfix();
|
||||
}
|
||||
|
||||
.carousel-item {
|
||||
position: relative;
|
||||
display: none;
|
||||
float: left;
|
||||
width: 100%;
|
||||
margin-right: -100%;
|
||||
backface-visibility: hidden;
|
||||
@include transition($carousel-transition);
|
||||
}
|
||||
|
||||
.carousel-item.active,
|
||||
.carousel-item-next,
|
||||
.carousel-item-prev {
|
||||
display: block;
|
||||
}
|
||||
|
||||
/* rtl:begin:ignore */
|
||||
.carousel-item-next:not(.carousel-item-start),
|
||||
.active.carousel-item-end {
|
||||
transform: translateX(100%);
|
||||
}
|
||||
|
||||
.carousel-item-prev:not(.carousel-item-end),
|
||||
.active.carousel-item-start {
|
||||
transform: translateX(-100%);
|
||||
}
|
||||
|
||||
/* rtl:end:ignore */
|
||||
|
||||
|
||||
//
|
||||
// Alternate transitions
|
||||
//
|
||||
|
||||
.carousel-fade {
|
||||
.carousel-item {
|
||||
opacity: 0;
|
||||
transition-property: opacity;
|
||||
transform: none;
|
||||
}
|
||||
|
||||
.carousel-item.active,
|
||||
.carousel-item-next.carousel-item-start,
|
||||
.carousel-item-prev.carousel-item-end {
|
||||
z-index: 1;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.active.carousel-item-start,
|
||||
.active.carousel-item-end {
|
||||
z-index: 0;
|
||||
opacity: 0;
|
||||
@include transition(opacity 0s $carousel-transition-duration);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Left/right controls for nav
|
||||
//
|
||||
|
||||
.carousel-control-prev,
|
||||
.carousel-control-next {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
z-index: 1;
|
||||
// Use flex for alignment (1-3)
|
||||
display: flex; // 1. allow flex styles
|
||||
align-items: center; // 2. vertically center contents
|
||||
justify-content: center; // 3. horizontally center contents
|
||||
width: $carousel-control-width;
|
||||
padding: 0;
|
||||
color: $carousel-control-color;
|
||||
text-align: center;
|
||||
background: none;
|
||||
border: 0;
|
||||
opacity: $carousel-control-opacity;
|
||||
@include transition($carousel-control-transition);
|
||||
|
||||
// Hover/focus state
|
||||
&:hover,
|
||||
&:focus {
|
||||
color: $carousel-control-color;
|
||||
text-decoration: none;
|
||||
outline: 0;
|
||||
opacity: $carousel-control-hover-opacity;
|
||||
}
|
||||
}
|
||||
.carousel-control-prev {
|
||||
left: 0;
|
||||
background-image: if($enable-gradients, linear-gradient(90deg, rgba($black, .25), rgba($black, .001)), null);
|
||||
}
|
||||
.carousel-control-next {
|
||||
right: 0;
|
||||
background-image: if($enable-gradients, linear-gradient(270deg, rgba($black, .25), rgba($black, .001)), null);
|
||||
}
|
||||
|
||||
// Icons for within
|
||||
.carousel-control-prev-icon,
|
||||
.carousel-control-next-icon {
|
||||
display: inline-block;
|
||||
width: $carousel-control-icon-width;
|
||||
height: $carousel-control-icon-width;
|
||||
background-repeat: no-repeat;
|
||||
background-position: 50%;
|
||||
background-size: 100% 100%;
|
||||
}
|
||||
|
||||
/* rtl:options: {
|
||||
"autoRename": true,
|
||||
"stringMap":[ {
|
||||
"name" : "prev-next",
|
||||
"search" : "prev",
|
||||
"replace" : "next"
|
||||
} ]
|
||||
} */
|
||||
.carousel-control-prev-icon {
|
||||
background-image: escape-svg($carousel-control-prev-icon-bg);
|
||||
}
|
||||
.carousel-control-next-icon {
|
||||
background-image: escape-svg($carousel-control-next-icon-bg);
|
||||
}
|
||||
|
||||
// Optional indicator pips/controls
|
||||
//
|
||||
// Add a container (such as a list) with the following class and add an item (ideally a focusable control,
|
||||
// like a button) with data-bs-target for each slide your carousel holds.
|
||||
|
||||
.carousel-indicators {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
z-index: 2;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
padding: 0;
|
||||
// Use the .carousel-control's width as margin so we don't overlay those
|
||||
margin-right: $carousel-control-width;
|
||||
margin-bottom: 1rem;
|
||||
margin-left: $carousel-control-width;
|
||||
list-style: none;
|
||||
|
||||
[data-bs-target] {
|
||||
box-sizing: content-box;
|
||||
flex: 0 1 auto;
|
||||
width: $carousel-indicator-width;
|
||||
height: $carousel-indicator-height;
|
||||
padding: 0;
|
||||
margin-right: $carousel-indicator-spacer;
|
||||
margin-left: $carousel-indicator-spacer;
|
||||
text-indent: -999px;
|
||||
cursor: pointer;
|
||||
background-color: $carousel-indicator-active-bg;
|
||||
background-clip: padding-box;
|
||||
border: 0;
|
||||
// Use transparent borders to increase the hit area by 10px on top and bottom.
|
||||
border-top: $carousel-indicator-hit-area-height solid transparent;
|
||||
border-bottom: $carousel-indicator-hit-area-height solid transparent;
|
||||
opacity: $carousel-indicator-opacity;
|
||||
@include transition($carousel-indicator-transition);
|
||||
}
|
||||
|
||||
.active {
|
||||
opacity: $carousel-indicator-active-opacity;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Optional captions
|
||||
//
|
||||
//
|
||||
|
||||
.carousel-caption {
|
||||
position: absolute;
|
||||
right: (100% - $carousel-caption-width) * .5;
|
||||
bottom: $carousel-caption-spacer;
|
||||
left: (100% - $carousel-caption-width) * .5;
|
||||
padding-top: $carousel-caption-padding-y;
|
||||
padding-bottom: $carousel-caption-padding-y;
|
||||
color: $carousel-caption-color;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
// Dark mode carousel
|
||||
|
||||
.carousel-dark {
|
||||
.carousel-control-prev-icon,
|
||||
.carousel-control-next-icon {
|
||||
filter: $carousel-dark-control-icon-filter;
|
||||
}
|
||||
|
||||
.carousel-indicators [data-bs-target] {
|
||||
background-color: $carousel-dark-indicator-active-bg;
|
||||
}
|
||||
|
||||
.carousel-caption {
|
||||
color: $carousel-dark-caption-color;
|
||||
}
|
||||
}
|
@ -1,40 +0,0 @@
|
||||
// transparent background and border properties included 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
|
||||
|
||||
.btn-close {
|
||||
box-sizing: content-box;
|
||||
width: $btn-close-width;
|
||||
height: $btn-close-height;
|
||||
padding: $btn-close-padding-y $btn-close-padding-x;
|
||||
color: $btn-close-color;
|
||||
background: transparent escape-svg($btn-close-bg) center / $btn-close-width auto no-repeat; // include transparent for button elements
|
||||
border: 0; // for button elements
|
||||
@include border-radius();
|
||||
opacity: $btn-close-opacity;
|
||||
|
||||
// Override <a>'s hover style
|
||||
&:hover {
|
||||
color: $btn-close-color;
|
||||
text-decoration: none;
|
||||
opacity: $btn-close-hover-opacity;
|
||||
}
|
||||
|
||||
&:focus {
|
||||
outline: 0;
|
||||
box-shadow: $btn-close-focus-shadow;
|
||||
opacity: $btn-close-focus-opacity;
|
||||
}
|
||||
|
||||
&:disabled,
|
||||
&.disabled {
|
||||
pointer-events: none;
|
||||
user-select: none;
|
||||
opacity: $btn-close-disabled-opacity;
|
||||
}
|
||||
}
|
||||
|
||||
.btn-close-white {
|
||||
filter: $btn-close-white-filter;
|
||||
}
|
@ -1,41 +0,0 @@
|
||||
// Container widths
|
||||
//
|
||||
// Set the container width, and override it for fixed navbars in media queries.
|
||||
|
||||
@if $enable-grid-classes {
|
||||
// Single container class with breakpoint max-widths
|
||||
.container,
|
||||
// 100% wide container at all breakpoints
|
||||
.container-fluid {
|
||||
@include make-container();
|
||||
}
|
||||
|
||||
// Responsive containers that are 100% wide until a breakpoint
|
||||
@each $breakpoint, $container-max-width in $container-max-widths {
|
||||
.container-#{$breakpoint} {
|
||||
@extend .container-fluid;
|
||||
}
|
||||
|
||||
@include media-breakpoint-up($breakpoint, $grid-breakpoints) {
|
||||
%responsive-container-#{$breakpoint} {
|
||||
max-width: $container-max-width;
|
||||
}
|
||||
|
||||
// Extend each breakpoint which is smaller or equal to the current breakpoint
|
||||
$extend-breakpoint: true;
|
||||
|
||||
@each $name, $width in $grid-breakpoints {
|
||||
@if ($extend-breakpoint) {
|
||||
.container#{breakpoint-infix($name, $grid-breakpoints)} {
|
||||
@extend %responsive-container-#{$breakpoint};
|
||||
}
|
||||
|
||||
// Once the current breakpoint is reached, stop extending
|
||||
@if ($breakpoint == $name) {
|
||||
$extend-breakpoint: false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,240 +0,0 @@
|
||||
// The dropdown wrapper (`<div>`)
|
||||
.dropup,
|
||||
.dropend,
|
||||
.dropdown,
|
||||
.dropstart {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.dropdown-toggle {
|
||||
white-space: nowrap;
|
||||
|
||||
// Generate the caret automatically
|
||||
@include caret();
|
||||
}
|
||||
|
||||
// The dropdown menu
|
||||
.dropdown-menu {
|
||||
position: absolute;
|
||||
z-index: $zindex-dropdown;
|
||||
display: none; // none by default, but block on "open" of the menu
|
||||
min-width: $dropdown-min-width;
|
||||
padding: $dropdown-padding-y $dropdown-padding-x;
|
||||
margin: 0; // Override default margin of ul
|
||||
@include font-size($dropdown-font-size);
|
||||
color: $dropdown-color;
|
||||
text-align: left; // Ensures proper alignment if parent has it changed (e.g., modal footer)
|
||||
list-style: none;
|
||||
background-color: $dropdown-bg;
|
||||
background-clip: padding-box;
|
||||
border: $dropdown-border-width solid $dropdown-border-color;
|
||||
@include border-radius($dropdown-border-radius);
|
||||
@include box-shadow($dropdown-box-shadow);
|
||||
|
||||
&[data-bs-popper] {
|
||||
top: 100%;
|
||||
left: 0;
|
||||
margin-top: $dropdown-spacer;
|
||||
}
|
||||
}
|
||||
|
||||
// scss-docs-start responsive-breakpoints
|
||||
// We deliberately hardcode the `bs-` prefix because we check
|
||||
// this custom property in JS to determine Popper's positioning
|
||||
|
||||
@each $breakpoint in map-keys($grid-breakpoints) {
|
||||
@include media-breakpoint-up($breakpoint) {
|
||||
$infix: breakpoint-infix($breakpoint, $grid-breakpoints);
|
||||
|
||||
.dropdown-menu#{$infix}-start {
|
||||
--bs-position: start;
|
||||
|
||||
&[data-bs-popper] {
|
||||
right: auto;
|
||||
left: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.dropdown-menu#{$infix}-end {
|
||||
--bs-position: end;
|
||||
|
||||
&[data-bs-popper] {
|
||||
right: 0;
|
||||
left: auto;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// scss-docs-end responsive-breakpoints
|
||||
|
||||
// Allow for dropdowns to go bottom up (aka, dropup-menu)
|
||||
// Just add .dropup after the standard .dropdown class and you're set.
|
||||
.dropup {
|
||||
.dropdown-menu[data-bs-popper] {
|
||||
top: auto;
|
||||
bottom: 100%;
|
||||
margin-top: 0;
|
||||
margin-bottom: $dropdown-spacer;
|
||||
}
|
||||
|
||||
.dropdown-toggle {
|
||||
@include caret(up);
|
||||
}
|
||||
}
|
||||
|
||||
.dropend {
|
||||
.dropdown-menu[data-bs-popper] {
|
||||
top: 0;
|
||||
right: auto;
|
||||
left: 100%;
|
||||
margin-top: 0;
|
||||
margin-left: $dropdown-spacer;
|
||||
}
|
||||
|
||||
.dropdown-toggle {
|
||||
@include caret(end);
|
||||
&::after {
|
||||
vertical-align: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.dropstart {
|
||||
.dropdown-menu[data-bs-popper] {
|
||||
top: 0;
|
||||
right: 100%;
|
||||
left: auto;
|
||||
margin-top: 0;
|
||||
margin-right: $dropdown-spacer;
|
||||
}
|
||||
|
||||
.dropdown-toggle {
|
||||
@include caret(start);
|
||||
&::before {
|
||||
vertical-align: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Dividers (basically an `<hr>`) within the dropdown
|
||||
.dropdown-divider {
|
||||
height: 0;
|
||||
margin: $dropdown-divider-margin-y 0;
|
||||
overflow: hidden;
|
||||
border-top: 1px solid $dropdown-divider-bg;
|
||||
}
|
||||
|
||||
// Links, buttons, and more within the dropdown menu
|
||||
//
|
||||
// `<button>`-specific styles are denoted with `// For <button>s`
|
||||
.dropdown-item {
|
||||
display: block;
|
||||
width: 100%; // For `<button>`s
|
||||
padding: $dropdown-item-padding-y $dropdown-item-padding-x;
|
||||
clear: both;
|
||||
font-weight: $font-weight-normal;
|
||||
color: $dropdown-link-color;
|
||||
text-align: inherit; // For `<button>`s
|
||||
text-decoration: if($link-decoration == none, null, none);
|
||||
white-space: nowrap; // prevent links from randomly breaking onto new lines
|
||||
background-color: transparent; // For `<button>`s
|
||||
border: 0; // For `<button>`s
|
||||
|
||||
// Prevent dropdown overflow if there's no padding
|
||||
// See https://github.com/twbs/bootstrap/pull/27703
|
||||
@if $dropdown-padding-y == 0 {
|
||||
&:first-child {
|
||||
@include border-top-radius($dropdown-inner-border-radius);
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
@include border-bottom-radius($dropdown-inner-border-radius);
|
||||
}
|
||||
}
|
||||
|
||||
&:hover,
|
||||
&:focus {
|
||||
color: $dropdown-link-hover-color;
|
||||
text-decoration: if($link-hover-decoration == underline, none, null);
|
||||
@include gradient-bg($dropdown-link-hover-bg);
|
||||
}
|
||||
|
||||
&.active,
|
||||
&:active {
|
||||
color: $dropdown-link-active-color;
|
||||
text-decoration: none;
|
||||
@include gradient-bg($dropdown-link-active-bg);
|
||||
}
|
||||
|
||||
&.disabled,
|
||||
&:disabled {
|
||||
color: $dropdown-link-disabled-color;
|
||||
pointer-events: none;
|
||||
background-color: transparent;
|
||||
// Remove CSS gradients if they're enabled
|
||||
background-image: if($enable-gradients, none, null);
|
||||
}
|
||||
}
|
||||
|
||||
.dropdown-menu.show {
|
||||
display: block;
|
||||
}
|
||||
|
||||
// Dropdown section headers
|
||||
.dropdown-header {
|
||||
display: block;
|
||||
padding: $dropdown-header-padding;
|
||||
margin-bottom: 0; // for use with heading elements
|
||||
@include font-size($font-size-sm);
|
||||
color: $dropdown-header-color;
|
||||
white-space: nowrap; // as with > li > a
|
||||
}
|
||||
|
||||
// Dropdown text
|
||||
.dropdown-item-text {
|
||||
display: block;
|
||||
padding: $dropdown-item-padding-y $dropdown-item-padding-x;
|
||||
color: $dropdown-link-color;
|
||||
}
|
||||
|
||||
// Dark dropdowns
|
||||
.dropdown-menu-dark {
|
||||
color: $dropdown-dark-color;
|
||||
background-color: $dropdown-dark-bg;
|
||||
border-color: $dropdown-dark-border-color;
|
||||
@include box-shadow($dropdown-dark-box-shadow);
|
||||
|
||||
.dropdown-item {
|
||||
color: $dropdown-dark-link-color;
|
||||
|
||||
&:hover,
|
||||
&:focus {
|
||||
color: $dropdown-dark-link-hover-color;
|
||||
@include gradient-bg($dropdown-dark-link-hover-bg);
|
||||
}
|
||||
|
||||
&.active,
|
||||
&:active {
|
||||
color: $dropdown-dark-link-active-color;
|
||||
@include gradient-bg($dropdown-dark-link-active-bg);
|
||||
}
|
||||
|
||||
&.disabled,
|
||||
&:disabled {
|
||||
color: $dropdown-dark-link-disabled-color;
|
||||
}
|
||||
}
|
||||
|
||||
.dropdown-divider {
|
||||
border-color: $dropdown-dark-divider-bg;
|
||||
}
|
||||
|
||||
.dropdown-item-text {
|
||||
color: $dropdown-dark-link-color;
|
||||
}
|
||||
|
||||
.dropdown-header {
|
||||
color: $dropdown-dark-header-color;
|
||||
}
|
||||
}
|
@ -1,9 +0,0 @@
|
||||
@import "forms/labels";
|
||||
@import "forms/form-text";
|
||||
@import "forms/form-control";
|
||||
@import "forms/form-select";
|
||||
@import "forms/form-check";
|
||||
@import "forms/form-range";
|
||||
@import "forms/floating-labels";
|
||||
@import "forms/input-group";
|
||||
@import "forms/validation";
|
@ -1,302 +0,0 @@
|
||||
// Bootstrap functions
|
||||
//
|
||||
// Utility mixins and functions for evaluating source code across our variables, maps, and mixins.
|
||||
|
||||
// Ascending
|
||||
// Used to evaluate Sass maps like our grid breakpoints.
|
||||
@mixin _assert-ascending($map, $map-name) {
|
||||
$prev-key: null;
|
||||
$prev-num: null;
|
||||
@each $key, $num in $map {
|
||||
@if $prev-num == null or unit($num) == "%" or unit($prev-num) == "%" {
|
||||
// Do nothing
|
||||
} @else if not comparable($prev-num, $num) {
|
||||
@warn "Potentially invalid value for #{$map-name}: This map must be in ascending order, but key '#{$key}' has value #{$num} whose unit makes it incomparable to #{$prev-num}, the value of the previous key '#{$prev-key}' !";
|
||||
} @else if $prev-num >= $num {
|
||||
@warn "Invalid value for #{$map-name}: This map must be in ascending order, but key '#{$key}' has value #{$num} which isn't greater than #{$prev-num}, the value of the previous key '#{$prev-key}' !";
|
||||
}
|
||||
$prev-key: $key;
|
||||
$prev-num: $num;
|
||||
}
|
||||
}
|
||||
|
||||
// Starts at zero
|
||||
// Used to ensure the min-width of the lowest breakpoint starts at 0.
|
||||
@mixin _assert-starts-at-zero($map, $map-name: "$grid-breakpoints") {
|
||||
@if length($map) > 0 {
|
||||
$values: map-values($map);
|
||||
$first-value: nth($values, 1);
|
||||
@if $first-value != 0 {
|
||||
@warn "First breakpoint in #{$map-name} must start at 0, but starts at #{$first-value}.";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Colors
|
||||
@function to-rgb($value) {
|
||||
@return red($value), green($value), blue($value);
|
||||
}
|
||||
|
||||
// stylelint-disable scss/dollar-variable-pattern
|
||||
@function rgba-css-var($identifier, $target) {
|
||||
@if $identifier == "body" and $target == "bg" {
|
||||
@return rgba(var(--#{$variable-prefix}#{$identifier}-bg-rgb), var(--#{$variable-prefix}#{$target}-opacity));
|
||||
} @if $identifier == "body" and $target == "text" {
|
||||
@return rgba(var(--#{$variable-prefix}#{$identifier}-color-rgb), var(--#{$variable-prefix}#{$target}-opacity));
|
||||
} @else {
|
||||
@return rgba(var(--#{$variable-prefix}#{$identifier}-rgb), var(--#{$variable-prefix}#{$target}-opacity));
|
||||
}
|
||||
}
|
||||
|
||||
@function map-loop($map, $func, $args...) {
|
||||
$_map: ();
|
||||
|
||||
@each $key, $value in $map {
|
||||
// allow to pass the $key and $value of the map as an function argument
|
||||
$_args: ();
|
||||
@each $arg in $args {
|
||||
$_args: append($_args, if($arg == "$key", $key, if($arg == "$value", $value, $arg)));
|
||||
}
|
||||
|
||||
$_map: map-merge($_map, ($key: call(get-function($func), $_args...)));
|
||||
}
|
||||
|
||||
@return $_map;
|
||||
}
|
||||
// stylelint-enable scss/dollar-variable-pattern
|
||||
|
||||
@function varify($list) {
|
||||
$result: null;
|
||||
@each $entry in $list {
|
||||
$result: append($result, var(--#{$variable-prefix}#{$entry}), space);
|
||||
}
|
||||
@return $result;
|
||||
}
|
||||
|
||||
// Internal Bootstrap function to turn maps into its negative variant.
|
||||
// It prefixes the keys with `n` and makes the value negative.
|
||||
@function negativify-map($map) {
|
||||
$result: ();
|
||||
@each $key, $value in $map {
|
||||
@if $key != 0 {
|
||||
$result: map-merge($result, ("n" + $key: (-$value)));
|
||||
}
|
||||
}
|
||||
@return $result;
|
||||
}
|
||||
|
||||
// Get multiple keys from a sass map
|
||||
@function map-get-multiple($map, $values) {
|
||||
$result: ();
|
||||
@each $key, $value in $map {
|
||||
@if (index($values, $key) != null) {
|
||||
$result: map-merge($result, ($key: $value));
|
||||
}
|
||||
}
|
||||
@return $result;
|
||||
}
|
||||
|
||||
// Merge multiple maps
|
||||
@function map-merge-multiple($maps...) {
|
||||
$merged-maps: ();
|
||||
|
||||
@each $map in $maps {
|
||||
$merged-maps: map-merge($merged-maps, $map);
|
||||
}
|
||||
@return $merged-maps;
|
||||
}
|
||||
|
||||
// Replace `$search` with `$replace` in `$string`
|
||||
// Used on our SVG icon backgrounds for custom forms.
|
||||
//
|
||||
// @author Hugo Giraudel
|
||||
// @param {String} $string - Initial string
|
||||
// @param {String} $search - Substring to replace
|
||||
// @param {String} $replace ('') - New value
|
||||
// @return {String} - Updated string
|
||||
@function str-replace($string, $search, $replace: "") {
|
||||
$index: str-index($string, $search);
|
||||
|
||||
@if $index {
|
||||
@return str-slice($string, 1, $index - 1) + $replace + str-replace(str-slice($string, $index + str-length($search)), $search, $replace);
|
||||
}
|
||||
|
||||
@return $string;
|
||||
}
|
||||
|
||||
// See https://codepen.io/kevinweber/pen/dXWoRw
|
||||
//
|
||||
// Requires the use of quotes around data URIs.
|
||||
|
||||
@function escape-svg($string) {
|
||||
@if str-index($string, "data:image/svg+xml") {
|
||||
@each $char, $encoded in $escaped-characters {
|
||||
// Do not escape the url brackets
|
||||
@if str-index($string, "url(") == 1 {
|
||||
$string: url("#{str-replace(str-slice($string, 6, -3), $char, $encoded)}");
|
||||
} @else {
|
||||
$string: str-replace($string, $char, $encoded);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@return $string;
|
||||
}
|
||||
|
||||
// Color contrast
|
||||
// See https://github.com/twbs/bootstrap/pull/30168
|
||||
|
||||
// A list of pre-calculated numbers of pow(divide((divide($value, 255) + .055), 1.055), 2.4). (from 0 to 255)
|
||||
// stylelint-disable-next-line scss/dollar-variable-default, scss/dollar-variable-pattern
|
||||
$_luminance-list: .0008 .001 .0011 .0013 .0015 .0017 .002 .0022 .0025 .0027 .003 .0033 .0037 .004 .0044 .0048 .0052 .0056 .006 .0065 .007 .0075 .008 .0086 .0091 .0097 .0103 .011 .0116 .0123 .013 .0137 .0144 .0152 .016 .0168 .0176 .0185 .0194 .0203 .0212 .0222 .0232 .0242 .0252 .0262 .0273 .0284 .0296 .0307 .0319 .0331 .0343 .0356 .0369 .0382 .0395 .0409 .0423 .0437 .0452 .0467 .0482 .0497 .0513 .0529 .0545 .0561 .0578 .0595 .0612 .063 .0648 .0666 .0685 .0704 .0723 .0742 .0762 .0782 .0802 .0823 .0844 .0865 .0887 .0908 .0931 .0953 .0976 .0999 .1022 .1046 .107 .1095 .1119 .1144 .117 .1195 .1221 .1248 .1274 .1301 .1329 .1356 .1384 .1413 .1441 .147 .15 .1529 .1559 .159 .162 .1651 .1683 .1714 .1746 .1779 .1812 .1845 .1878 .1912 .1946 .1981 .2016 .2051 .2086 .2122 .2159 .2195 .2232 .227 .2307 .2346 .2384 .2423 .2462 .2502 .2542 .2582 .2623 .2664 .2705 .2747 .2789 .2831 .2874 .2918 .2961 .3005 .305 .3095 .314 .3185 .3231 .3278 .3325 .3372 .3419 .3467 .3515 .3564 .3613 .3663 .3712 .3763 .3813 .3864 .3916 .3968 .402 .4072 .4125 .4179 .4233 .4287 .4342 .4397 .4452 .4508 .4564 .4621 .4678 .4735 .4793 .4851 .491 .4969 .5029 .5089 .5149 .521 .5271 .5333 .5395 .5457 .552 .5583 .5647 .5711 .5776 .5841 .5906 .5972 .6038 .6105 .6172 .624 .6308 .6376 .6445 .6514 .6584 .6654 .6724 .6795 .6867 .6939 .7011 .7084 .7157 .7231 .7305 .7379 .7454 .7529 .7605 .7682 .7758 .7835 .7913 .7991 .807 .8148 .8228 .8308 .8388 .8469 .855 .8632 .8714 .8796 .8879 .8963 .9047 .9131 .9216 .9301 .9387 .9473 .956 .9647 .9734 .9823 .9911 1;
|
||||
|
||||
@function color-contrast($background, $color-contrast-dark: $color-contrast-dark, $color-contrast-light: $color-contrast-light, $min-contrast-ratio: $min-contrast-ratio) {
|
||||
$foregrounds: $color-contrast-light, $color-contrast-dark, $white, $black;
|
||||
$max-ratio: 0;
|
||||
$max-ratio-color: null;
|
||||
|
||||
@each $color in $foregrounds {
|
||||
$contrast-ratio: contrast-ratio($background, $color);
|
||||
@if $contrast-ratio > $min-contrast-ratio {
|
||||
@return $color;
|
||||
} @else if $contrast-ratio > $max-ratio {
|
||||
$max-ratio: $contrast-ratio;
|
||||
$max-ratio-color: $color;
|
||||
}
|
||||
}
|
||||
|
||||
@warn "Found no color leading to #{$min-contrast-ratio}:1 contrast ratio against #{$background}...";
|
||||
|
||||
@return $max-ratio-color;
|
||||
}
|
||||
|
||||
@function contrast-ratio($background, $foreground: $color-contrast-light) {
|
||||
$l1: luminance($background);
|
||||
$l2: luminance(opaque($background, $foreground));
|
||||
|
||||
@return if($l1 > $l2, divide($l1 + .05, $l2 + .05), divide($l2 + .05, $l1 + .05));
|
||||
}
|
||||
|
||||
// Return WCAG2.0 relative luminance
|
||||
// See https://www.w3.org/WAI/GL/wiki/Relative_luminance
|
||||
// See https://www.w3.org/TR/WCAG20-TECHS/G17.html#G17-tests
|
||||
@function luminance($color) {
|
||||
$rgb: (
|
||||
"r": red($color),
|
||||
"g": green($color),
|
||||
"b": blue($color)
|
||||
);
|
||||
|
||||
@each $name, $value in $rgb {
|
||||
$value: if(divide($value, 255) < .03928, divide(divide($value, 255), 12.92), nth($_luminance-list, $value + 1));
|
||||
$rgb: map-merge($rgb, ($name: $value));
|
||||
}
|
||||
|
||||
@return (map-get($rgb, "r") * .2126) + (map-get($rgb, "g") * .7152) + (map-get($rgb, "b") * .0722);
|
||||
}
|
||||
|
||||
// Return opaque color
|
||||
// opaque(#fff, rgba(0, 0, 0, .5)) => #808080
|
||||
@function opaque($background, $foreground) {
|
||||
@return mix(rgba($foreground, 1), $background, opacity($foreground) * 100);
|
||||
}
|
||||
|
||||
// scss-docs-start color-functions
|
||||
// Tint a color: mix a color with white
|
||||
@function tint-color($color, $weight) {
|
||||
@return mix(white, $color, $weight);
|
||||
}
|
||||
|
||||
// Shade a color: mix a color with black
|
||||
@function shade-color($color, $weight) {
|
||||
@return mix(black, $color, $weight);
|
||||
}
|
||||
|
||||
// Shade the color if the weight is positive, else tint it
|
||||
@function shift-color($color, $weight) {
|
||||
@return if($weight > 0, shade-color($color, $weight), tint-color($color, -$weight));
|
||||
}
|
||||
// scss-docs-end color-functions
|
||||
|
||||
// Return valid calc
|
||||
@function add($value1, $value2, $return-calc: true) {
|
||||
@if $value1 == null {
|
||||
@return $value2;
|
||||
}
|
||||
|
||||
@if $value2 == null {
|
||||
@return $value1;
|
||||
}
|
||||
|
||||
@if type-of($value1) == number and type-of($value2) == number and comparable($value1, $value2) {
|
||||
@return $value1 + $value2;
|
||||
}
|
||||
|
||||
@return if($return-calc == true, calc(#{$value1} + #{$value2}), $value1 + unquote(" + ") + $value2);
|
||||
}
|
||||
|
||||
@function subtract($value1, $value2, $return-calc: true) {
|
||||
@if $value1 == null and $value2 == null {
|
||||
@return null;
|
||||
}
|
||||
|
||||
@if $value1 == null {
|
||||
@return -$value2;
|
||||
}
|
||||
|
||||
@if $value2 == null {
|
||||
@return $value1;
|
||||
}
|
||||
|
||||
@if type-of($value1) == number and type-of($value2) == number and comparable($value1, $value2) {
|
||||
@return $value1 - $value2;
|
||||
}
|
||||
|
||||
@if type-of($value2) != number {
|
||||
$value2: unquote("(") + $value2 + unquote(")");
|
||||
}
|
||||
|
||||
@return if($return-calc == true, calc(#{$value1} - #{$value2}), $value1 + unquote(" - ") + $value2);
|
||||
}
|
||||
|
||||
@function divide($dividend, $divisor, $precision: 10) {
|
||||
$sign: if($dividend > 0 and $divisor > 0 or $dividend < 0 and $divisor < 0, 1, -1);
|
||||
$dividend: abs($dividend);
|
||||
$divisor: abs($divisor);
|
||||
@if $dividend == 0 {
|
||||
@return 0;
|
||||
}
|
||||
@if $divisor == 0 {
|
||||
@error "Cannot divide by 0";
|
||||
}
|
||||
$remainder: $dividend;
|
||||
$result: 0;
|
||||
$factor: 10;
|
||||
@while ($remainder > 0 and $precision >= 0) {
|
||||
$quotient: 0;
|
||||
@while ($remainder >= $divisor) {
|
||||
$remainder: $remainder - $divisor;
|
||||
$quotient: $quotient + 1;
|
||||
}
|
||||
$result: $result * 10 + $quotient;
|
||||
$factor: $factor * .1;
|
||||
$remainder: $remainder * 10;
|
||||
$precision: $precision - 1;
|
||||
@if ($precision < 0 and $remainder >= $divisor * 5) {
|
||||
$result: $result + 1;
|
||||
}
|
||||
}
|
||||
$result: $result * $factor * $sign;
|
||||
$dividend-unit: unit($dividend);
|
||||
$divisor-unit: unit($divisor);
|
||||
$unit-map: (
|
||||
"px": 1px,
|
||||
"rem": 1rem,
|
||||
"em": 1em,
|
||||
"%": 1%
|
||||
);
|
||||
@if ($dividend-unit != $divisor-unit and map-has-key($unit-map, $dividend-unit)) {
|
||||
$result: $result * map-get($unit-map, $dividend-unit);
|
||||
}
|
||||
@return $result;
|
||||
}
|
@ -1,33 +0,0 @@
|
||||
// Row
|
||||
//
|
||||
// Rows contain your columns.
|
||||
|
||||
@if $enable-grid-classes {
|
||||
.row {
|
||||
@include make-row();
|
||||
|
||||
> * {
|
||||
@include make-col-ready();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@if $enable-cssgrid {
|
||||
.grid {
|
||||
display: grid;
|
||||
grid-template-rows: repeat(var(--#{$variable-prefix}rows, 1), 1fr);
|
||||
grid-template-columns: repeat(var(--#{$variable-prefix}columns, #{$grid-columns}), 1fr);
|
||||
gap: var(--#{$variable-prefix}gap, #{$grid-gutter-width});
|
||||
|
||||
@include make-cssgrid();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Columns
|
||||
//
|
||||
// Common styles for small and large grid columns
|
||||
|
||||
@if $enable-grid-classes {
|
||||
@include make-grid-columns();
|
||||
}
|
@ -1,9 +0,0 @@
|
||||
@import "helpers/clearfix";
|
||||
@import "helpers/colored-links";
|
||||
@import "helpers/ratio";
|
||||
@import "helpers/position";
|
||||
@import "helpers/stacks";
|
||||
@import "helpers/visually-hidden";
|
||||
@import "helpers/stretched-link";
|
||||
@import "helpers/text-truncation";
|
||||
@import "helpers/vr";
|
@ -1,42 +0,0 @@
|
||||
// Responsive images (ensure images don't scale beyond their parents)
|
||||
//
|
||||
// This is purposefully opt-in via an explicit class rather than being the default for all `<img>`s.
|
||||
// We previously tried the "images are responsive by default" approach in Bootstrap v2,
|
||||
// and abandoned it in Bootstrap v3 because it breaks lots of third-party widgets (including Google Maps)
|
||||
// which weren't expecting the images within themselves to be involuntarily resized.
|
||||
// See also https://github.com/twbs/bootstrap/issues/18178
|
||||
.img-fluid {
|
||||
@include img-fluid();
|
||||
}
|
||||
|
||||
|
||||
// Image thumbnails
|
||||
.img-thumbnail {
|
||||
padding: $thumbnail-padding;
|
||||
background-color: $thumbnail-bg;
|
||||
border: $thumbnail-border-width solid $thumbnail-border-color;
|
||||
@include border-radius($thumbnail-border-radius);
|
||||
@include box-shadow($thumbnail-box-shadow);
|
||||
|
||||
// Keep them at most 100% wide
|
||||
@include img-fluid();
|
||||
}
|
||||
|
||||
//
|
||||
// Figures
|
||||
//
|
||||
|
||||
.figure {
|
||||
// Ensures the caption's text aligns with the image.
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.figure-img {
|
||||
margin-bottom: $spacer * .5;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.figure-caption {
|
||||
@include font-size($figure-caption-font-size);
|
||||
color: $figure-caption-color;
|
||||
}
|
@ -1,174 +0,0 @@
|
||||
// Base class
|
||||
//
|
||||
// Easily usable on <ul>, <ol>, or <div>.
|
||||
|
||||
.list-group {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
// No need to set list-style: none; since .list-group-item is block level
|
||||
padding-left: 0; // reset padding because ul and ol
|
||||
margin-bottom: 0;
|
||||
@include border-radius($list-group-border-radius);
|
||||
}
|
||||
|
||||
.list-group-numbered {
|
||||
list-style-type: none;
|
||||
counter-reset: section;
|
||||
|
||||
> li::before {
|
||||
// Increments only this instance of the section counter
|
||||
content: counters(section, ".") ". ";
|
||||
counter-increment: section;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Interactive list items
|
||||
//
|
||||
// Use anchor or button elements instead of `li`s or `div`s to create interactive
|
||||
// list items. Includes an extra `.active` modifier class for selected items.
|
||||
|
||||
.list-group-item-action {
|
||||
width: 100%; // For `<button>`s (anchors become 100% by default though)
|
||||
color: $list-group-action-color;
|
||||
text-align: inherit; // For `<button>`s (anchors inherit)
|
||||
|
||||
// Hover state
|
||||
&:hover,
|
||||
&:focus {
|
||||
z-index: 1; // Place hover/focus items above their siblings for proper border styling
|
||||
color: $list-group-action-hover-color;
|
||||
text-decoration: none;
|
||||
background-color: $list-group-hover-bg;
|
||||
}
|
||||
|
||||
&:active {
|
||||
color: $list-group-action-active-color;
|
||||
background-color: $list-group-action-active-bg;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Individual list items
|
||||
//
|
||||
// Use on `li`s or `div`s within the `.list-group` parent.
|
||||
|
||||
.list-group-item {
|
||||
position: relative;
|
||||
display: block;
|
||||
padding: $list-group-item-padding-y $list-group-item-padding-x;
|
||||
color: $list-group-color;
|
||||
text-decoration: if($link-decoration == none, null, none);
|
||||
background-color: $list-group-bg;
|
||||
border: $list-group-border-width solid $list-group-border-color;
|
||||
|
||||
&:first-child {
|
||||
@include border-top-radius(inherit);
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
@include border-bottom-radius(inherit);
|
||||
}
|
||||
|
||||
&.disabled,
|
||||
&:disabled {
|
||||
color: $list-group-disabled-color;
|
||||
pointer-events: none;
|
||||
background-color: $list-group-disabled-bg;
|
||||
}
|
||||
|
||||
// Include both here for `<a>`s and `<button>`s
|
||||
&.active {
|
||||
z-index: 2; // Place active items above their siblings for proper border styling
|
||||
color: $list-group-active-color;
|
||||
background-color: $list-group-active-bg;
|
||||
border-color: $list-group-active-border-color;
|
||||
}
|
||||
|
||||
& + & {
|
||||
border-top-width: 0;
|
||||
|
||||
&.active {
|
||||
margin-top: -$list-group-border-width;
|
||||
border-top-width: $list-group-border-width;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Horizontal
|
||||
//
|
||||
// Change the layout of list group items from vertical (default) to horizontal.
|
||||
|
||||
@each $breakpoint in map-keys($grid-breakpoints) {
|
||||
@include media-breakpoint-up($breakpoint) {
|
||||
$infix: breakpoint-infix($breakpoint, $grid-breakpoints);
|
||||
|
||||
.list-group-horizontal#{$infix} {
|
||||
flex-direction: row;
|
||||
|
||||
> .list-group-item {
|
||||
&:first-child {
|
||||
@include border-bottom-start-radius($list-group-border-radius);
|
||||
@include border-top-end-radius(0);
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
@include border-top-end-radius($list-group-border-radius);
|
||||
@include border-bottom-start-radius(0);
|
||||
}
|
||||
|
||||
&.active {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
+ .list-group-item {
|
||||
border-top-width: $list-group-border-width;
|
||||
border-left-width: 0;
|
||||
|
||||
&.active {
|
||||
margin-left: -$list-group-border-width;
|
||||
border-left-width: $list-group-border-width;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Flush list items
|
||||
//
|
||||
// Remove borders and border-radius to keep list group items edge-to-edge. Most
|
||||
// useful within other components (e.g., cards).
|
||||
|
||||
.list-group-flush {
|
||||
@include border-radius(0);
|
||||
|
||||
> .list-group-item {
|
||||
border-width: 0 0 $list-group-border-width;
|
||||
|
||||
&:last-child {
|
||||
border-bottom-width: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// scss-docs-start list-group-modifiers
|
||||
// List group contextual variants
|
||||
//
|
||||
// Add modifier classes to change text and background color on individual items.
|
||||
// Organizationally, this must come after the `:hover` states.
|
||||
|
||||
@each $state, $value in $theme-colors {
|
||||
$list-group-variant-bg: shift-color($value, $list-group-item-bg-scale);
|
||||
$list-group-variant-color: shift-color($value, $list-group-item-color-scale);
|
||||
@if (contrast-ratio($list-group-variant-bg, $list-group-variant-color) < $min-contrast-ratio) {
|
||||
$list-group-variant-color: mix($value, color-contrast($list-group-variant-bg), abs($list-group-item-color-scale));
|
||||
}
|
||||
|
||||
@include list-group-item-variant($state, $list-group-variant-bg, $list-group-variant-color);
|
||||
}
|
||||
// scss-docs-end list-group-modifiers
|
@ -1,43 +0,0 @@
|
||||
// Toggles
|
||||
//
|
||||
// Used in conjunction with global variables to enable certain theme features.
|
||||
|
||||
// Vendor
|
||||
@import "vendor/rfs";
|
||||
|
||||
// Deprecate
|
||||
@import "mixins/deprecate";
|
||||
|
||||
// Helpers
|
||||
@import "mixins/breakpoints";
|
||||
@import "mixins/color-scheme";
|
||||
@import "mixins/image";
|
||||
@import "mixins/resize";
|
||||
@import "mixins/visually-hidden";
|
||||
@import "mixins/reset-text";
|
||||
@import "mixins/text-truncate";
|
||||
|
||||
// Utilities
|
||||
@import "mixins/utilities";
|
||||
|
||||
// Components
|
||||
@import "mixins/alert";
|
||||
@import "mixins/backdrop";
|
||||
@import "mixins/buttons";
|
||||
@import "mixins/caret";
|
||||
@import "mixins/pagination";
|
||||
@import "mixins/lists";
|
||||
@import "mixins/list-group";
|
||||
@import "mixins/forms";
|
||||
@import "mixins/table-variants";
|
||||
|
||||
// Skins
|
||||
@import "mixins/border-radius";
|
||||
@import "mixins/box-shadow";
|
||||
@import "mixins/gradients";
|
||||
@import "mixins/transition";
|
||||
|
||||
// Layout
|
||||
@import "mixins/clearfix";
|
||||
@import "mixins/container";
|
||||
@import "mixins/grid";
|
@ -1,209 +0,0 @@
|
||||
// .modal-open - body class for killing the scroll
|
||||
// .modal - container to scroll within
|
||||
// .modal-dialog - positioning shell for the actual modal
|
||||
// .modal-content - actual modal w/ bg and corners and stuff
|
||||
|
||||
|
||||
// Container that the modal scrolls within
|
||||
.modal {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
z-index: $zindex-modal;
|
||||
display: none;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto;
|
||||
// Prevent Chrome on Windows from adding a focus outline. For details, see
|
||||
// https://github.com/twbs/bootstrap/pull/10951.
|
||||
outline: 0;
|
||||
// We deliberately don't use `-webkit-overflow-scrolling: touch;` due to a
|
||||
// gnarly iOS Safari bug: https://bugs.webkit.org/show_bug.cgi?id=158342
|
||||
// See also https://github.com/twbs/bootstrap/issues/17695
|
||||
}
|
||||
|
||||
// Shell div to position the modal with bottom padding
|
||||
.modal-dialog {
|
||||
position: relative;
|
||||
width: auto;
|
||||
margin: $modal-dialog-margin;
|
||||
// allow clicks to pass through for custom click handling to close modal
|
||||
pointer-events: none;
|
||||
|
||||
// When fading in the modal, animate it to slide down
|
||||
.modal.fade & {
|
||||
@include transition($modal-transition);
|
||||
transform: $modal-fade-transform;
|
||||
}
|
||||
.modal.show & {
|
||||
transform: $modal-show-transform;
|
||||
}
|
||||
|
||||
// When trying to close, animate focus to scale
|
||||
.modal.modal-static & {
|
||||
transform: $modal-scale-transform;
|
||||
}
|
||||
}
|
||||
|
||||
.modal-dialog-scrollable {
|
||||
height: subtract(100%, $modal-dialog-margin * 2);
|
||||
|
||||
.modal-content {
|
||||
max-height: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.modal-body {
|
||||
overflow-y: auto;
|
||||
}
|
||||
}
|
||||
|
||||
.modal-dialog-centered {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
min-height: subtract(100%, $modal-dialog-margin * 2);
|
||||
}
|
||||
|
||||
// Actual modal
|
||||
.modal-content {
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 100%; // Ensure `.modal-content` extends the full width of the parent `.modal-dialog`
|
||||
// counteract the pointer-events: none; in the .modal-dialog
|
||||
color: $modal-content-color;
|
||||
pointer-events: auto;
|
||||
background-color: $modal-content-bg;
|
||||
background-clip: padding-box;
|
||||
border: $modal-content-border-width solid $modal-content-border-color;
|
||||
@include border-radius($modal-content-border-radius);
|
||||
@include box-shadow($modal-content-box-shadow-xs);
|
||||
// Remove focus outline from opened modal
|
||||
outline: 0;
|
||||
}
|
||||
|
||||
// Modal background
|
||||
.modal-backdrop {
|
||||
@include overlay-backdrop($zindex-modal-backdrop, $modal-backdrop-bg, $modal-backdrop-opacity);
|
||||
}
|
||||
|
||||
// Modal header
|
||||
// Top section of the modal w/ title and dismiss
|
||||
.modal-header {
|
||||
display: flex;
|
||||
flex-shrink: 0;
|
||||
align-items: center;
|
||||
justify-content: space-between; // Put modal header elements (title and dismiss) on opposite ends
|
||||
padding: $modal-header-padding;
|
||||
border-bottom: $modal-header-border-width solid $modal-header-border-color;
|
||||
@include border-top-radius($modal-content-inner-border-radius);
|
||||
|
||||
.btn-close {
|
||||
padding: ($modal-header-padding-y * .5) ($modal-header-padding-x * .5);
|
||||
margin: ($modal-header-padding-y * -.5) ($modal-header-padding-x * -.5) ($modal-header-padding-y * -.5) auto;
|
||||
}
|
||||
}
|
||||
|
||||
// Title text within header
|
||||
.modal-title {
|
||||
margin-bottom: 0;
|
||||
line-height: $modal-title-line-height;
|
||||
}
|
||||
|
||||
// Modal body
|
||||
// Where all modal content resides (sibling of .modal-header and .modal-footer)
|
||||
.modal-body {
|
||||
position: relative;
|
||||
// Enable `flex-grow: 1` so that the body take up as much space as possible
|
||||
// when there should be a fixed height on `.modal-dialog`.
|
||||
flex: 1 1 auto;
|
||||
padding: $modal-inner-padding;
|
||||
}
|
||||
|
||||
// Footer (for actions)
|
||||
.modal-footer {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
flex-shrink: 0;
|
||||
align-items: center; // vertically center
|
||||
justify-content: flex-end; // Right align buttons with flex property because text-align doesn't work on flex items
|
||||
padding: $modal-inner-padding - $modal-footer-margin-between * .5;
|
||||
border-top: $modal-footer-border-width solid $modal-footer-border-color;
|
||||
@include border-bottom-radius($modal-content-inner-border-radius);
|
||||
|
||||
// Place margin between footer elements
|
||||
// This solution is far from ideal because of the universal selector usage,
|
||||
// but is needed to fix https://github.com/twbs/bootstrap/issues/24800
|
||||
> * {
|
||||
margin: $modal-footer-margin-between * .5;
|
||||
}
|
||||
}
|
||||
|
||||
// Scale up the modal
|
||||
@include media-breakpoint-up(sm) {
|
||||
// Automatically set modal's width for larger viewports
|
||||
.modal-dialog {
|
||||
max-width: $modal-md;
|
||||
margin: $modal-dialog-margin-y-sm-up auto;
|
||||
}
|
||||
|
||||
.modal-dialog-scrollable {
|
||||
height: subtract(100%, $modal-dialog-margin-y-sm-up * 2);
|
||||
}
|
||||
|
||||
.modal-dialog-centered {
|
||||
min-height: subtract(100%, $modal-dialog-margin-y-sm-up * 2);
|
||||
}
|
||||
|
||||
.modal-content {
|
||||
@include box-shadow($modal-content-box-shadow-sm-up);
|
||||
}
|
||||
|
||||
.modal-sm { max-width: $modal-sm; }
|
||||
}
|
||||
|
||||
@include media-breakpoint-up(lg) {
|
||||
.modal-lg,
|
||||
.modal-xl {
|
||||
max-width: $modal-lg;
|
||||
}
|
||||
}
|
||||
|
||||
@include media-breakpoint-up(xl) {
|
||||
.modal-xl { max-width: $modal-xl; }
|
||||
}
|
||||
|
||||
// scss-docs-start modal-fullscreen-loop
|
||||
@each $breakpoint in map-keys($grid-breakpoints) {
|
||||
$infix: breakpoint-infix($breakpoint, $grid-breakpoints);
|
||||
$postfix: if($infix != "", $infix + "-down", "");
|
||||
|
||||
@include media-breakpoint-down($breakpoint) {
|
||||
.modal-fullscreen#{$postfix} {
|
||||
width: 100vw;
|
||||
max-width: none;
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
|
||||
.modal-content {
|
||||
height: 100%;
|
||||
border: 0;
|
||||
@include border-radius(0);
|
||||
}
|
||||
|
||||
.modal-header {
|
||||
@include border-radius(0);
|
||||
}
|
||||
|
||||
.modal-body {
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.modal-footer {
|
||||
@include border-radius(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// scss-docs-end modal-fullscreen-loop
|
@ -1,139 +0,0 @@
|
||||
// Base class
|
||||
//
|
||||
// Kickstart any navigation component with a set of style resets. Works with
|
||||
// `<nav>`s, `<ul>`s or `<ol>`s.
|
||||
|
||||
.nav {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
padding-left: 0;
|
||||
margin-bottom: 0;
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
.nav-link {
|
||||
display: block;
|
||||
padding: $nav-link-padding-y $nav-link-padding-x;
|
||||
@include font-size($nav-link-font-size);
|
||||
font-weight: $nav-link-font-weight;
|
||||
color: $nav-link-color;
|
||||
text-decoration: if($link-decoration == none, null, none);
|
||||
@include transition($nav-link-transition);
|
||||
|
||||
&:hover,
|
||||
&:focus {
|
||||
color: $nav-link-hover-color;
|
||||
text-decoration: if($link-hover-decoration == underline, none, null);
|
||||
}
|
||||
|
||||
// Disabled state lightens text
|
||||
&.disabled {
|
||||
color: $nav-link-disabled-color;
|
||||
pointer-events: none;
|
||||
cursor: default;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Tabs
|
||||
//
|
||||
|
||||
.nav-tabs {
|
||||
border-bottom: $nav-tabs-border-width solid $nav-tabs-border-color;
|
||||
|
||||
.nav-link {
|
||||
margin-bottom: -$nav-tabs-border-width;
|
||||
background: none;
|
||||
border: $nav-tabs-border-width solid transparent;
|
||||
@include border-top-radius($nav-tabs-border-radius);
|
||||
|
||||
&:hover,
|
||||
&:focus {
|
||||
border-color: $nav-tabs-link-hover-border-color;
|
||||
// Prevents active .nav-link tab overlapping focus outline of previous/next .nav-link
|
||||
isolation: isolate;
|
||||
}
|
||||
|
||||
&.disabled {
|
||||
color: $nav-link-disabled-color;
|
||||
background-color: transparent;
|
||||
border-color: transparent;
|
||||
}
|
||||
}
|
||||
|
||||
.nav-link.active,
|
||||
.nav-item.show .nav-link {
|
||||
color: $nav-tabs-link-active-color;
|
||||
background-color: $nav-tabs-link-active-bg;
|
||||
border-color: $nav-tabs-link-active-border-color;
|
||||
}
|
||||
|
||||
.dropdown-menu {
|
||||
// Make dropdown border overlap tab border
|
||||
margin-top: -$nav-tabs-border-width;
|
||||
// Remove the top rounded corners here since there is a hard edge above the menu
|
||||
@include border-top-radius(0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Pills
|
||||
//
|
||||
|
||||
.nav-pills {
|
||||
.nav-link {
|
||||
background: none;
|
||||
border: 0;
|
||||
@include border-radius($nav-pills-border-radius);
|
||||
}
|
||||
|
||||
.nav-link.active,
|
||||
.show > .nav-link {
|
||||
color: $nav-pills-link-active-color;
|
||||
@include gradient-bg($nav-pills-link-active-bg);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Justified variants
|
||||
//
|
||||
|
||||
.nav-fill {
|
||||
> .nav-link,
|
||||
.nav-item {
|
||||
flex: 1 1 auto;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
|
||||
.nav-justified {
|
||||
> .nav-link,
|
||||
.nav-item {
|
||||
flex-basis: 0;
|
||||
flex-grow: 1;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
|
||||
.nav-fill,
|
||||
.nav-justified {
|
||||
.nav-item .nav-link {
|
||||
width: 100%; // Make sure button will grow
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Tabbable tabs
|
||||
//
|
||||
// Hide tabbable panes to start, show them when `.active`
|
||||
|
||||
.tab-content {
|
||||
> .tab-pane {
|
||||
display: none;
|
||||
}
|
||||
> .active {
|
||||
display: block;
|
||||
}
|
||||
}
|
@ -1,335 +0,0 @@
|
||||
// Contents
|
||||
//
|
||||
// Navbar
|
||||
// Navbar brand
|
||||
// Navbar nav
|
||||
// Navbar text
|
||||
// Responsive navbar
|
||||
// Navbar position
|
||||
// Navbar themes
|
||||
|
||||
|
||||
// Navbar
|
||||
//
|
||||
// Provide a static navbar from which we expand to create full-width, fixed, and
|
||||
// other navbar variations.
|
||||
|
||||
.navbar {
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-wrap: wrap; // allow us to do the line break for collapsing content
|
||||
align-items: center;
|
||||
justify-content: space-between; // space out brand from logo
|
||||
padding-top: $navbar-padding-y;
|
||||
padding-right: $navbar-padding-x; // default: null
|
||||
padding-bottom: $navbar-padding-y;
|
||||
padding-left: $navbar-padding-x; // default: null
|
||||
@include gradient-bg();
|
||||
|
||||
// Because flex properties aren't inherited, we need to redeclare these first
|
||||
// few properties so that content nested within behave properly.
|
||||
// The `flex-wrap` property is inherited to simplify the expanded navbars
|
||||
%container-flex-properties {
|
||||
display: flex;
|
||||
flex-wrap: inherit;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
> .container,
|
||||
> .container-fluid {
|
||||
@extend %container-flex-properties;
|
||||
}
|
||||
|
||||
@each $breakpoint, $container-max-width in $container-max-widths {
|
||||
> .container#{breakpoint-infix($breakpoint, $container-max-widths)} {
|
||||
@extend %container-flex-properties;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Navbar brand
|
||||
//
|
||||
// Used for brand, project, or site names.
|
||||
|
||||
.navbar-brand {
|
||||
padding-top: $navbar-brand-padding-y;
|
||||
padding-bottom: $navbar-brand-padding-y;
|
||||
margin-right: $navbar-brand-margin-end;
|
||||
@include font-size($navbar-brand-font-size);
|
||||
text-decoration: if($link-decoration == none, null, none);
|
||||
white-space: nowrap;
|
||||
|
||||
&:hover,
|
||||
&:focus {
|
||||
text-decoration: if($link-hover-decoration == underline, none, null);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Navbar nav
|
||||
//
|
||||
// Custom navbar navigation (doesn't require `.nav`, but does make use of `.nav-link`).
|
||||
|
||||
.navbar-nav {
|
||||
display: flex;
|
||||
flex-direction: column; // cannot use `inherit` to get the `.navbar`s value
|
||||
padding-left: 0;
|
||||
margin-bottom: 0;
|
||||
list-style: none;
|
||||
|
||||
.nav-link {
|
||||
padding-right: 0;
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
.dropdown-menu {
|
||||
position: static;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Navbar text
|
||||
//
|
||||
//
|
||||
|
||||
.navbar-text {
|
||||
padding-top: $nav-link-padding-y;
|
||||
padding-bottom: $nav-link-padding-y;
|
||||
}
|
||||
|
||||
|
||||
// Responsive navbar
|
||||
//
|
||||
// Custom styles for responsive collapsing and toggling of navbar contents.
|
||||
// Powered by the collapse Bootstrap JavaScript plugin.
|
||||
|
||||
// When collapsed, prevent the toggleable navbar contents from appearing in
|
||||
// the default flexbox row orientation. Requires the use of `flex-wrap: wrap`
|
||||
// on the `.navbar` parent.
|
||||
.navbar-collapse {
|
||||
flex-basis: 100%;
|
||||
flex-grow: 1;
|
||||
// For always expanded or extra full navbars, ensure content aligns itself
|
||||
// properly vertically. Can be easily overridden with flex utilities.
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
// Button for toggling the navbar when in its collapsed state
|
||||
.navbar-toggler {
|
||||
padding: $navbar-toggler-padding-y $navbar-toggler-padding-x;
|
||||
@include font-size($navbar-toggler-font-size);
|
||||
line-height: 1;
|
||||
background-color: transparent; // remove default button style
|
||||
border: $border-width solid transparent; // remove default button style
|
||||
@include border-radius($navbar-toggler-border-radius);
|
||||
@include transition($navbar-toggler-transition);
|
||||
|
||||
&:hover {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
&:focus {
|
||||
text-decoration: none;
|
||||
outline: 0;
|
||||
box-shadow: 0 0 0 $navbar-toggler-focus-width;
|
||||
}
|
||||
}
|
||||
|
||||
// Keep as a separate element so folks can easily override it with another icon
|
||||
// or image file as needed.
|
||||
.navbar-toggler-icon {
|
||||
display: inline-block;
|
||||
width: 1.5em;
|
||||
height: 1.5em;
|
||||
vertical-align: middle;
|
||||
background-repeat: no-repeat;
|
||||
background-position: center;
|
||||
background-size: 100%;
|
||||
}
|
||||
|
||||
.navbar-nav-scroll {
|
||||
max-height: var(--#{$variable-prefix}scroll-height, 75vh);
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
// scss-docs-start navbar-expand-loop
|
||||
// Generate series of `.navbar-expand-*` responsive classes for configuring
|
||||
// where your navbar collapses.
|
||||
.navbar-expand {
|
||||
@each $breakpoint in map-keys($grid-breakpoints) {
|
||||
$next: breakpoint-next($breakpoint, $grid-breakpoints);
|
||||
$infix: breakpoint-infix($next, $grid-breakpoints);
|
||||
|
||||
// stylelint-disable-next-line scss/selector-no-union-class-name
|
||||
&#{$infix} {
|
||||
@include media-breakpoint-up($next) {
|
||||
flex-wrap: nowrap;
|
||||
justify-content: flex-start;
|
||||
|
||||
.navbar-nav {
|
||||
flex-direction: row;
|
||||
|
||||
.dropdown-menu {
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
.nav-link {
|
||||
padding-right: $navbar-nav-link-padding-x;
|
||||
padding-left: $navbar-nav-link-padding-x;
|
||||
}
|
||||
}
|
||||
|
||||
.navbar-nav-scroll {
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
.navbar-collapse {
|
||||
display: flex !important; // stylelint-disable-line declaration-no-important
|
||||
flex-basis: auto;
|
||||
}
|
||||
|
||||
.navbar-toggler {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.offcanvas-header {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.offcanvas {
|
||||
position: inherit;
|
||||
bottom: 0;
|
||||
z-index: 1000;
|
||||
flex-grow: 1;
|
||||
visibility: visible !important; // stylelint-disable-line declaration-no-important
|
||||
background-color: transparent;
|
||||
border-right: 0;
|
||||
border-left: 0;
|
||||
@include transition(none);
|
||||
transform: none;
|
||||
}
|
||||
.offcanvas-top,
|
||||
.offcanvas-bottom {
|
||||
height: auto;
|
||||
border-top: 0;
|
||||
border-bottom: 0;
|
||||
}
|
||||
|
||||
.offcanvas-body {
|
||||
display: flex;
|
||||
flex-grow: 0;
|
||||
padding: 0;
|
||||
overflow-y: visible;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// scss-docs-end navbar-expand-loop
|
||||
|
||||
// Navbar themes
|
||||
//
|
||||
// Styles for switching between navbars with light or dark background.
|
||||
|
||||
// Dark links against a light background
|
||||
.navbar-light {
|
||||
.navbar-brand {
|
||||
color: $navbar-light-brand-color;
|
||||
|
||||
&:hover,
|
||||
&:focus {
|
||||
color: $navbar-light-brand-hover-color;
|
||||
}
|
||||
}
|
||||
|
||||
.navbar-nav {
|
||||
.nav-link {
|
||||
color: $navbar-light-color;
|
||||
|
||||
&:hover,
|
||||
&:focus {
|
||||
color: $navbar-light-hover-color;
|
||||
}
|
||||
|
||||
&.disabled {
|
||||
color: $navbar-light-disabled-color;
|
||||
}
|
||||
}
|
||||
|
||||
.show > .nav-link,
|
||||
.nav-link.active {
|
||||
color: $navbar-light-active-color;
|
||||
}
|
||||
}
|
||||
|
||||
.navbar-toggler {
|
||||
color: $navbar-light-color;
|
||||
border-color: $navbar-light-toggler-border-color;
|
||||
}
|
||||
|
||||
.navbar-toggler-icon {
|
||||
background-image: escape-svg($navbar-light-toggler-icon-bg);
|
||||
}
|
||||
|
||||
.navbar-text {
|
||||
color: $navbar-light-color;
|
||||
|
||||
a,
|
||||
a:hover,
|
||||
a:focus {
|
||||
color: $navbar-light-active-color;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// White links against a dark background
|
||||
.navbar-dark {
|
||||
.navbar-brand {
|
||||
color: $navbar-dark-brand-color;
|
||||
|
||||
&:hover,
|
||||
&:focus {
|
||||
color: $navbar-dark-brand-hover-color;
|
||||
}
|
||||
}
|
||||
|
||||
.navbar-nav {
|
||||
.nav-link {
|
||||
color: $navbar-dark-color;
|
||||
|
||||
&:hover,
|
||||
&:focus {
|
||||
color: $navbar-dark-hover-color;
|
||||
}
|
||||
|
||||
&.disabled {
|
||||
color: $navbar-dark-disabled-color;
|
||||
}
|
||||
}
|
||||
|
||||
.show > .nav-link,
|
||||
.nav-link.active {
|
||||
color: $navbar-dark-active-color;
|
||||
}
|
||||
}
|
||||
|
||||
.navbar-toggler {
|
||||
color: $navbar-dark-color;
|
||||
border-color: $navbar-dark-toggler-border-color;
|
||||
}
|
||||
|
||||
.navbar-toggler-icon {
|
||||
background-image: escape-svg($navbar-dark-toggler-icon-bg);
|
||||
}
|
||||
|
||||
.navbar-text {
|
||||
color: $navbar-dark-color;
|
||||
a,
|
||||
a:hover,
|
||||
a:focus {
|
||||
color: $navbar-dark-active-color;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,83 +0,0 @@
|
||||
.offcanvas {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
z-index: $zindex-offcanvas;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
max-width: 100%;
|
||||
color: $offcanvas-color;
|
||||
visibility: hidden;
|
||||
background-color: $offcanvas-bg-color;
|
||||
background-clip: padding-box;
|
||||
outline: 0;
|
||||
@include box-shadow($offcanvas-box-shadow);
|
||||
@include transition(transform $offcanvas-transition-duration ease-in-out);
|
||||
}
|
||||
|
||||
.offcanvas-backdrop {
|
||||
@include overlay-backdrop($zindex-offcanvas-backdrop, $offcanvas-backdrop-bg, $offcanvas-backdrop-opacity);
|
||||
}
|
||||
|
||||
.offcanvas-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: $offcanvas-padding-y $offcanvas-padding-x;
|
||||
|
||||
.btn-close {
|
||||
padding: ($offcanvas-padding-y * .5) ($offcanvas-padding-x * .5);
|
||||
margin-top: $offcanvas-padding-y * -.5;
|
||||
margin-right: $offcanvas-padding-x * -.5;
|
||||
margin-bottom: $offcanvas-padding-y * -.5;
|
||||
}
|
||||
}
|
||||
|
||||
.offcanvas-title {
|
||||
margin-bottom: 0;
|
||||
line-height: $offcanvas-title-line-height;
|
||||
}
|
||||
|
||||
.offcanvas-body {
|
||||
flex-grow: 1;
|
||||
padding: $offcanvas-padding-y $offcanvas-padding-x;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.offcanvas-start {
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: $offcanvas-horizontal-width;
|
||||
border-right: $offcanvas-border-width solid $offcanvas-border-color;
|
||||
transform: translateX(-100%);
|
||||
}
|
||||
|
||||
.offcanvas-end {
|
||||
top: 0;
|
||||
right: 0;
|
||||
width: $offcanvas-horizontal-width;
|
||||
border-left: $offcanvas-border-width solid $offcanvas-border-color;
|
||||
transform: translateX(100%);
|
||||
}
|
||||
|
||||
.offcanvas-top {
|
||||
top: 0;
|
||||
right: 0;
|
||||
left: 0;
|
||||
height: $offcanvas-vertical-height;
|
||||
max-height: 100%;
|
||||
border-bottom: $offcanvas-border-width solid $offcanvas-border-color;
|
||||
transform: translateY(-100%);
|
||||
}
|
||||
|
||||
.offcanvas-bottom {
|
||||
right: 0;
|
||||
left: 0;
|
||||
height: $offcanvas-vertical-height;
|
||||
max-height: 100%;
|
||||
border-top: $offcanvas-border-width solid $offcanvas-border-color;
|
||||
transform: translateY(100%);
|
||||
}
|
||||
|
||||
.offcanvas.show {
|
||||
transform: none;
|
||||
}
|
@ -1,64 +0,0 @@
|
||||
.pagination {
|
||||
display: flex;
|
||||
@include list-unstyled();
|
||||
}
|
||||
|
||||
.page-link {
|
||||
position: relative;
|
||||
display: block;
|
||||
color: $pagination-color;
|
||||
text-decoration: if($link-decoration == none, null, none);
|
||||
background-color: $pagination-bg;
|
||||
border: $pagination-border-width solid $pagination-border-color;
|
||||
@include transition($pagination-transition);
|
||||
|
||||
&:hover {
|
||||
z-index: 2;
|
||||
color: $pagination-hover-color;
|
||||
text-decoration: if($link-hover-decoration == underline, none, null);
|
||||
background-color: $pagination-hover-bg;
|
||||
border-color: $pagination-hover-border-color;
|
||||
}
|
||||
|
||||
&:focus {
|
||||
z-index: 3;
|
||||
color: $pagination-focus-color;
|
||||
background-color: $pagination-focus-bg;
|
||||
outline: $pagination-focus-outline;
|
||||
box-shadow: $pagination-focus-box-shadow;
|
||||
}
|
||||
}
|
||||
|
||||
.page-item {
|
||||
&:not(:first-child) .page-link {
|
||||
margin-left: $pagination-margin-start;
|
||||
}
|
||||
|
||||
&.active .page-link {
|
||||
z-index: 3;
|
||||
color: $pagination-active-color;
|
||||
@include gradient-bg($pagination-active-bg);
|
||||
border-color: $pagination-active-border-color;
|
||||
}
|
||||
|
||||
&.disabled .page-link {
|
||||
color: $pagination-disabled-color;
|
||||
pointer-events: none;
|
||||
background-color: $pagination-disabled-bg;
|
||||
border-color: $pagination-disabled-border-color;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Sizing
|
||||
//
|
||||
@include pagination-size($pagination-padding-y, $pagination-padding-x, null, $pagination-border-radius);
|
||||
|
||||
.pagination-lg {
|
||||
@include pagination-size($pagination-padding-y-lg, $pagination-padding-x-lg, $font-size-lg, $pagination-border-radius-lg);
|
||||
}
|
||||
|
||||
.pagination-sm {
|
||||
@include pagination-size($pagination-padding-y-sm, $pagination-padding-x-sm, $font-size-sm, $pagination-border-radius-sm);
|
||||
}
|
@ -1,51 +0,0 @@
|
||||
.placeholder {
|
||||
display: inline-block;
|
||||
min-height: 1em;
|
||||
vertical-align: middle;
|
||||
cursor: wait;
|
||||
background-color: currentColor;
|
||||
opacity: $placeholder-opacity-max;
|
||||
|
||||
&.btn::before {
|
||||
display: inline-block;
|
||||
content: "";
|
||||
}
|
||||
}
|
||||
|
||||
// Sizing
|
||||
.placeholder-xs {
|
||||
min-height: .6em;
|
||||
}
|
||||
|
||||
.placeholder-sm {
|
||||
min-height: .8em;
|
||||
}
|
||||
|
||||
.placeholder-lg {
|
||||
min-height: 1.2em;
|
||||
}
|
||||
|
||||
// Animation
|
||||
.placeholder-glow {
|
||||
.placeholder {
|
||||
animation: placeholder-glow 2s ease-in-out infinite;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes placeholder-glow {
|
||||
50% {
|
||||
opacity: $placeholder-opacity-min;
|
||||
}
|
||||
}
|
||||
|
||||
.placeholder-wave {
|
||||
mask-image: linear-gradient(130deg, $black 55%, rgba(0, 0, 0, (1 - $placeholder-opacity-min)) 75%, $black 95%);
|
||||
mask-size: 200% 100%;
|
||||
animation: placeholder-wave 2s linear infinite;
|
||||
}
|
||||
|
||||
@keyframes placeholder-wave {
|
||||
100% {
|
||||
mask-position: -200% 0%;
|
||||
}
|
||||
}
|
@ -1,158 +0,0 @@
|
||||
.popover {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0 #{"/* rtl:ignore */"};
|
||||
z-index: $zindex-popover;
|
||||
display: block;
|
||||
max-width: $popover-max-width;
|
||||
// Our parent element can be arbitrary since tooltips are by default inserted as a sibling of their target element.
|
||||
// So reset our font and text properties to avoid inheriting weird values.
|
||||
@include reset-text();
|
||||
@include font-size($popover-font-size);
|
||||
// Allow breaking very long words so they don't overflow the popover's bounds
|
||||
word-wrap: break-word;
|
||||
background-color: $popover-bg;
|
||||
background-clip: padding-box;
|
||||
border: $popover-border-width solid $popover-border-color;
|
||||
@include border-radius($popover-border-radius);
|
||||
@include box-shadow($popover-box-shadow);
|
||||
|
||||
.popover-arrow {
|
||||
position: absolute;
|
||||
display: block;
|
||||
width: $popover-arrow-width;
|
||||
height: $popover-arrow-height;
|
||||
|
||||
&::before,
|
||||
&::after {
|
||||
position: absolute;
|
||||
display: block;
|
||||
content: "";
|
||||
border-color: transparent;
|
||||
border-style: solid;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.bs-popover-top {
|
||||
> .popover-arrow {
|
||||
bottom: subtract(-$popover-arrow-height, $popover-border-width);
|
||||
|
||||
&::before {
|
||||
bottom: 0;
|
||||
border-width: $popover-arrow-height ($popover-arrow-width * .5) 0;
|
||||
border-top-color: $popover-arrow-outer-color;
|
||||
}
|
||||
|
||||
&::after {
|
||||
bottom: $popover-border-width;
|
||||
border-width: $popover-arrow-height ($popover-arrow-width * .5) 0;
|
||||
border-top-color: $popover-arrow-color;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.bs-popover-end {
|
||||
> .popover-arrow {
|
||||
left: subtract(-$popover-arrow-height, $popover-border-width);
|
||||
width: $popover-arrow-height;
|
||||
height: $popover-arrow-width;
|
||||
|
||||
&::before {
|
||||
left: 0;
|
||||
border-width: ($popover-arrow-width * .5) $popover-arrow-height ($popover-arrow-width * .5) 0;
|
||||
border-right-color: $popover-arrow-outer-color;
|
||||
}
|
||||
|
||||
&::after {
|
||||
left: $popover-border-width;
|
||||
border-width: ($popover-arrow-width * .5) $popover-arrow-height ($popover-arrow-width * .5) 0;
|
||||
border-right-color: $popover-arrow-color;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.bs-popover-bottom {
|
||||
> .popover-arrow {
|
||||
top: subtract(-$popover-arrow-height, $popover-border-width);
|
||||
|
||||
&::before {
|
||||
top: 0;
|
||||
border-width: 0 ($popover-arrow-width * .5) $popover-arrow-height ($popover-arrow-width * .5);
|
||||
border-bottom-color: $popover-arrow-outer-color;
|
||||
}
|
||||
|
||||
&::after {
|
||||
top: $popover-border-width;
|
||||
border-width: 0 ($popover-arrow-width * .5) $popover-arrow-height ($popover-arrow-width * .5);
|
||||
border-bottom-color: $popover-arrow-color;
|
||||
}
|
||||
}
|
||||
|
||||
// This will remove the popover-header's border just below the arrow
|
||||
.popover-header::before {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 50%;
|
||||
display: block;
|
||||
width: $popover-arrow-width;
|
||||
margin-left: -$popover-arrow-width * .5;
|
||||
content: "";
|
||||
border-bottom: $popover-border-width solid $popover-header-bg;
|
||||
}
|
||||
}
|
||||
|
||||
.bs-popover-start {
|
||||
> .popover-arrow {
|
||||
right: subtract(-$popover-arrow-height, $popover-border-width);
|
||||
width: $popover-arrow-height;
|
||||
height: $popover-arrow-width;
|
||||
|
||||
&::before {
|
||||
right: 0;
|
||||
border-width: ($popover-arrow-width * .5) 0 ($popover-arrow-width * .5) $popover-arrow-height;
|
||||
border-left-color: $popover-arrow-outer-color;
|
||||
}
|
||||
|
||||
&::after {
|
||||
right: $popover-border-width;
|
||||
border-width: ($popover-arrow-width * .5) 0 ($popover-arrow-width * .5) $popover-arrow-height;
|
||||
border-left-color: $popover-arrow-color;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.bs-popover-auto {
|
||||
&[data-popper-placement^="top"] {
|
||||
@extend .bs-popover-top;
|
||||
}
|
||||
&[data-popper-placement^="right"] {
|
||||
@extend .bs-popover-end;
|
||||
}
|
||||
&[data-popper-placement^="bottom"] {
|
||||
@extend .bs-popover-bottom;
|
||||
}
|
||||
&[data-popper-placement^="left"] {
|
||||
@extend .bs-popover-start;
|
||||
}
|
||||
}
|
||||
|
||||
// Offset the popover to account for the popover arrow
|
||||
.popover-header {
|
||||
padding: $popover-header-padding-y $popover-header-padding-x;
|
||||
margin-bottom: 0; // Reset the default from Reboot
|
||||
@include font-size($font-size-base);
|
||||
color: $popover-header-color;
|
||||
background-color: $popover-header-bg;
|
||||
border-bottom: $popover-border-width solid $popover-border-color;
|
||||
@include border-top-radius($popover-inner-border-radius);
|
||||
|
||||
&:empty {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.popover-body {
|
||||
padding: $popover-body-padding-y $popover-body-padding-x;
|
||||
color: $popover-body-color;
|
||||
}
|
@ -1,48 +0,0 @@
|
||||
// Disable animation if transitions are disabled
|
||||
|
||||
// scss-docs-start progress-keyframes
|
||||
@if $enable-transitions {
|
||||
@keyframes progress-bar-stripes {
|
||||
0% { background-position-x: $progress-height; }
|
||||
}
|
||||
}
|
||||
// scss-docs-end progress-keyframes
|
||||
|
||||
.progress {
|
||||
display: flex;
|
||||
height: $progress-height;
|
||||
overflow: hidden; // force rounded corners by cropping it
|
||||
@include font-size($progress-font-size);
|
||||
background-color: $progress-bg;
|
||||
@include border-radius($progress-border-radius);
|
||||
@include box-shadow($progress-box-shadow);
|
||||
}
|
||||
|
||||
.progress-bar {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
overflow: hidden;
|
||||
color: $progress-bar-color;
|
||||
text-align: center;
|
||||
white-space: nowrap;
|
||||
background-color: $progress-bar-bg;
|
||||
@include transition($progress-bar-transition);
|
||||
}
|
||||
|
||||
.progress-bar-striped {
|
||||
@include gradient-striped();
|
||||
background-size: $progress-height $progress-height;
|
||||
}
|
||||
|
||||
@if $enable-transitions {
|
||||
.progress-bar-animated {
|
||||
animation: $progress-bar-animation-timing progress-bar-stripes;
|
||||
|
||||
@if $enable-reduced-motion {
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
animation: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,625 +0,0 @@
|
||||
// stylelint-disable declaration-no-important, selector-no-qualifying-type, property-no-vendor-prefix
|
||||
|
||||
|
||||
// Reboot
|
||||
//
|
||||
// Normalization of HTML elements, manually forked from Normalize.css to remove
|
||||
// styles targeting irrelevant browsers while applying new styles.
|
||||
//
|
||||
// Normalize is licensed MIT. https://github.com/necolas/normalize.css
|
||||
|
||||
|
||||
// Document
|
||||
//
|
||||
// Change from `box-sizing: content-box` so that `width` is not affected by `padding` or `border`.
|
||||
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
|
||||
// Root
|
||||
//
|
||||
// Ability to the value of the root font sizes, affecting the value of `rem`.
|
||||
// null by default, thus nothing is generated.
|
||||
|
||||
:root {
|
||||
@if $font-size-root != null {
|
||||
font-size: var(--#{$variable-prefix}root-font-size);
|
||||
}
|
||||
|
||||
@if $enable-smooth-scroll {
|
||||
@media (prefers-reduced-motion: no-preference) {
|
||||
scroll-behavior: smooth;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Body
|
||||
//
|
||||
// 1. Remove the margin in all browsers.
|
||||
// 2. As a best practice, apply a default `background-color`.
|
||||
// 3. Prevent adjustments of font size after orientation changes in iOS.
|
||||
// 4. Change the default tap highlight to be completely transparent in iOS.
|
||||
|
||||
// scss-docs-start reboot-body-rules
|
||||
body {
|
||||
margin: 0; // 1
|
||||
font-family: var(--#{$variable-prefix}body-font-family);
|
||||
@include font-size(var(--#{$variable-prefix}body-font-size));
|
||||
font-weight: var(--#{$variable-prefix}body-font-weight);
|
||||
line-height: var(--#{$variable-prefix}body-line-height);
|
||||
color: var(--#{$variable-prefix}body-color);
|
||||
text-align: var(--#{$variable-prefix}body-text-align);
|
||||
background-color: var(--#{$variable-prefix}body-bg); // 2
|
||||
-webkit-text-size-adjust: 100%; // 3
|
||||
-webkit-tap-highlight-color: rgba($black, 0); // 4
|
||||
}
|
||||
// scss-docs-end reboot-body-rules
|
||||
|
||||
|
||||
// Content grouping
|
||||
//
|
||||
// 1. Reset Firefox's gray color
|
||||
// 2. Set correct height and prevent the `size` attribute to make the `hr` look like an input field
|
||||
|
||||
hr {
|
||||
margin: $hr-margin-y 0;
|
||||
color: $hr-color; // 1
|
||||
background-color: currentColor;
|
||||
border: 0;
|
||||
opacity: $hr-opacity;
|
||||
}
|
||||
|
||||
hr:not([size]) {
|
||||
height: $hr-height; // 2
|
||||
}
|
||||
|
||||
|
||||
// Typography
|
||||
//
|
||||
// 1. Remove top margins from headings
|
||||
// By default, `<h1>`-`<h6>` all receive top and bottom margins. We nuke the top
|
||||
// margin for easier control within type scales as it avoids margin collapsing.
|
||||
|
||||
%heading {
|
||||
margin-top: 0; // 1
|
||||
margin-bottom: $headings-margin-bottom;
|
||||
font-family: $headings-font-family;
|
||||
font-style: $headings-font-style;
|
||||
font-weight: $headings-font-weight;
|
||||
line-height: $headings-line-height;
|
||||
color: $headings-color;
|
||||
}
|
||||
|
||||
h1 {
|
||||
@extend %heading;
|
||||
@include font-size($h1-font-size);
|
||||
}
|
||||
|
||||
h2 {
|
||||
@extend %heading;
|
||||
@include font-size($h2-font-size);
|
||||
}
|
||||
|
||||
h3 {
|
||||
@extend %heading;
|
||||
@include font-size($h3-font-size);
|
||||
}
|
||||
|
||||
h4 {
|
||||
@extend %heading;
|
||||
@include font-size($h4-font-size);
|
||||
}
|
||||
|
||||
h5 {
|
||||
@extend %heading;
|
||||
@include font-size($h5-font-size);
|
||||
}
|
||||
|
||||
h6 {
|
||||
@extend %heading;
|
||||
@include font-size($h6-font-size);
|
||||
}
|
||||
|
||||
|
||||
// Reset margins on paragraphs
|
||||
//
|
||||
// Similarly, the top margin on `<p>`s get reset. However, we also reset the
|
||||
// bottom margin to use `rem` units instead of `em`.
|
||||
|
||||
p {
|
||||
margin-top: 0;
|
||||
margin-bottom: $paragraph-margin-bottom;
|
||||
}
|
||||
|
||||
|
||||
// Abbreviations
|
||||
//
|
||||
// 1. Duplicate behavior to the data-bs-* attribute for our tooltip plugin
|
||||
// 2. Add the correct text decoration in Chrome, Edge, Opera, and Safari.
|
||||
// 3. Add explicit cursor to indicate changed behavior.
|
||||
// 4. Prevent the text-decoration to be skipped.
|
||||
|
||||
abbr[title],
|
||||
abbr[data-bs-original-title] { // 1
|
||||
text-decoration: underline dotted; // 2
|
||||
cursor: help; // 3
|
||||
text-decoration-skip-ink: none; // 4
|
||||
}
|
||||
|
||||
|
||||
// Address
|
||||
|
||||
address {
|
||||
margin-bottom: 1rem;
|
||||
font-style: normal;
|
||||
line-height: inherit;
|
||||
}
|
||||
|
||||
|
||||
// Lists
|
||||
|
||||
ol,
|
||||
ul {
|
||||
padding-left: 2rem;
|
||||
}
|
||||
|
||||
ol,
|
||||
ul,
|
||||
dl {
|
||||
margin-top: 0;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
ol ol,
|
||||
ul ul,
|
||||
ol ul,
|
||||
ul ol {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
dt {
|
||||
font-weight: $dt-font-weight;
|
||||
}
|
||||
|
||||
// 1. Undo browser default
|
||||
|
||||
dd {
|
||||
margin-bottom: .5rem;
|
||||
margin-left: 0; // 1
|
||||
}
|
||||
|
||||
|
||||
// Blockquote
|
||||
|
||||
blockquote {
|
||||
margin: 0 0 1rem;
|
||||
}
|
||||
|
||||
|
||||
// Strong
|
||||
//
|
||||
// Add the correct font weight in Chrome, Edge, and Safari
|
||||
|
||||
b,
|
||||
strong {
|
||||
font-weight: $font-weight-bolder;
|
||||
}
|
||||
|
||||
|
||||
// Small
|
||||
//
|
||||
// Add the correct font size in all browsers
|
||||
|
||||
small {
|
||||
@include font-size($small-font-size);
|
||||
}
|
||||
|
||||
|
||||
// Mark
|
||||
|
||||
mark {
|
||||
padding: $mark-padding;
|
||||
background-color: $mark-bg;
|
||||
}
|
||||
|
||||
|
||||
// Sub and Sup
|
||||
//
|
||||
// Prevent `sub` and `sup` elements from affecting the line height in
|
||||
// all browsers.
|
||||
|
||||
sub,
|
||||
sup {
|
||||
position: relative;
|
||||
@include font-size($sub-sup-font-size);
|
||||
line-height: 0;
|
||||
vertical-align: baseline;
|
||||
}
|
||||
|
||||
sub { bottom: -.25em; }
|
||||
sup { top: -.5em; }
|
||||
|
||||
|
||||
// Links
|
||||
|
||||
a {
|
||||
color: $link-color;
|
||||
text-decoration: $link-decoration;
|
||||
|
||||
&:hover {
|
||||
color: $link-hover-color;
|
||||
text-decoration: $link-hover-decoration;
|
||||
}
|
||||
}
|
||||
|
||||
// And undo these styles for placeholder links/named anchors (without href).
|
||||
// It would be more straightforward to just use a[href] in previous block, but that
|
||||
// causes specificity issues in many other styles that are too complex to fix.
|
||||
// See https://github.com/twbs/bootstrap/issues/19402
|
||||
|
||||
a:not([href]):not([class]) {
|
||||
&,
|
||||
&:hover {
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Code
|
||||
|
||||
pre,
|
||||
code,
|
||||
kbd,
|
||||
samp {
|
||||
font-family: $font-family-code;
|
||||
@include font-size(1em); // Correct the odd `em` font sizing in all browsers.
|
||||
direction: ltr #{"/* rtl:ignore */"};
|
||||
unicode-bidi: bidi-override;
|
||||
}
|
||||
|
||||
// 1. Remove browser default top margin
|
||||
// 2. Reset browser default of `1em` to use `rem`s
|
||||
// 3. Don't allow content to break outside
|
||||
|
||||
pre {
|
||||
display: block;
|
||||
margin-top: 0; // 1
|
||||
margin-bottom: 1rem; // 2
|
||||
overflow: auto; // 3
|
||||
@include font-size($code-font-size);
|
||||
color: $pre-color;
|
||||
|
||||
// Account for some code outputs that place code tags in pre tags
|
||||
code {
|
||||
@include font-size(inherit);
|
||||
color: inherit;
|
||||
word-break: normal;
|
||||
}
|
||||
}
|
||||
|
||||
code {
|
||||
@include font-size($code-font-size);
|
||||
color: $code-color;
|
||||
word-wrap: break-word;
|
||||
|
||||
// Streamline the style when inside anchors to avoid broken underline and more
|
||||
a > & {
|
||||
color: inherit;
|
||||
}
|
||||
}
|
||||
|
||||
kbd {
|
||||
padding: $kbd-padding-y $kbd-padding-x;
|
||||
@include font-size($kbd-font-size);
|
||||
color: $kbd-color;
|
||||
background-color: $kbd-bg;
|
||||
@include border-radius($border-radius-sm);
|
||||
|
||||
kbd {
|
||||
padding: 0;
|
||||
@include font-size(1em);
|
||||
font-weight: $nested-kbd-font-weight;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Figures
|
||||
//
|
||||
// Apply a consistent margin strategy (matches our type styles).
|
||||
|
||||
figure {
|
||||
margin: 0 0 1rem;
|
||||
}
|
||||
|
||||
|
||||
// Images and content
|
||||
|
||||
img,
|
||||
svg {
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
|
||||
// Tables
|
||||
//
|
||||
// Prevent double borders
|
||||
|
||||
table {
|
||||
caption-side: bottom;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
caption {
|
||||
padding-top: $table-cell-padding-y;
|
||||
padding-bottom: $table-cell-padding-y;
|
||||
color: $table-caption-color;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
// 1. Removes font-weight bold by inheriting
|
||||
// 2. Matches default `<td>` alignment by inheriting `text-align`.
|
||||
// 3. Fix alignment for Safari
|
||||
|
||||
th {
|
||||
font-weight: $table-th-font-weight; // 1
|
||||
text-align: inherit; // 2
|
||||
text-align: -webkit-match-parent; // 3
|
||||
}
|
||||
|
||||
thead,
|
||||
tbody,
|
||||
tfoot,
|
||||
tr,
|
||||
td,
|
||||
th {
|
||||
border-color: inherit;
|
||||
border-style: solid;
|
||||
border-width: 0;
|
||||
}
|
||||
|
||||
|
||||
// Forms
|
||||
//
|
||||
// 1. Allow labels to use `margin` for spacing.
|
||||
|
||||
label {
|
||||
display: inline-block; // 1
|
||||
}
|
||||
|
||||
// Remove the default `border-radius` that macOS Chrome adds.
|
||||
// See https://github.com/twbs/bootstrap/issues/24093
|
||||
|
||||
button {
|
||||
// stylelint-disable-next-line property-disallowed-list
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
// Explicitly remove focus outline in Chromium when it shouldn't be
|
||||
// visible (e.g. as result of mouse click or touch tap). It already
|
||||
// should be doing this automatically, but seems to currently be
|
||||
// confused and applies its very visible two-tone outline anyway.
|
||||
|
||||
button:focus:not(:focus-visible) {
|
||||
outline: 0;
|
||||
}
|
||||
|
||||
// 1. Remove the margin in Firefox and Safari
|
||||
|
||||
input,
|
||||
button,
|
||||
select,
|
||||
optgroup,
|
||||
textarea {
|
||||
margin: 0; // 1
|
||||
font-family: inherit;
|
||||
@include font-size(inherit);
|
||||
line-height: inherit;
|
||||
}
|
||||
|
||||
// Remove the inheritance of text transform in Firefox
|
||||
button,
|
||||
select {
|
||||
text-transform: none;
|
||||
}
|
||||
// Set the cursor for non-`<button>` buttons
|
||||
//
|
||||
// Details at https://github.com/twbs/bootstrap/pull/30562
|
||||
[role="button"] {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
select {
|
||||
// Remove the inheritance of word-wrap in Safari.
|
||||
// See https://github.com/twbs/bootstrap/issues/24990
|
||||
word-wrap: normal;
|
||||
|
||||
// Undo the opacity change from Chrome
|
||||
&:disabled {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Remove the dropdown arrow in Chrome from inputs built with datalists.
|
||||
// See https://stackoverflow.com/a/54997118
|
||||
|
||||
[list]::-webkit-calendar-picker-indicator {
|
||||
display: none;
|
||||
}
|
||||
|
||||
// 1. Prevent a WebKit bug where (2) destroys native `audio` and `video`
|
||||
// controls in Android 4.
|
||||
// 2. Correct the inability to style clickable types in iOS and Safari.
|
||||
// 3. Opinionated: add "hand" cursor to non-disabled button elements.
|
||||
|
||||
button,
|
||||
[type="button"], // 1
|
||||
[type="reset"],
|
||||
[type="submit"] {
|
||||
-webkit-appearance: button; // 2
|
||||
|
||||
@if $enable-button-pointers {
|
||||
&:not(:disabled) {
|
||||
cursor: pointer; // 3
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Remove inner border and padding from Firefox, but don't restore the outline like Normalize.
|
||||
|
||||
::-moz-focus-inner {
|
||||
padding: 0;
|
||||
border-style: none;
|
||||
}
|
||||
|
||||
// 1. Textareas should really only resize vertically so they don't break their (horizontal) containers.
|
||||
|
||||
textarea {
|
||||
resize: vertical; // 1
|
||||
}
|
||||
|
||||
// 1. Browsers set a default `min-width: min-content;` on fieldsets,
|
||||
// unlike e.g. `<div>`s, which have `min-width: 0;` by default.
|
||||
// So we reset that to ensure fieldsets behave more like a standard block element.
|
||||
// See https://github.com/twbs/bootstrap/issues/12359
|
||||
// and https://html.spec.whatwg.org/multipage/#the-fieldset-and-legend-elements
|
||||
// 2. Reset the default outline behavior of fieldsets so they don't affect page layout.
|
||||
|
||||
fieldset {
|
||||
min-width: 0; // 1
|
||||
padding: 0; // 2
|
||||
margin: 0; // 2
|
||||
border: 0; // 2
|
||||
}
|
||||
|
||||
// 1. By using `float: left`, the legend will behave like a block element.
|
||||
// This way the border of a fieldset wraps around the legend if present.
|
||||
// 2. Fix wrapping bug.
|
||||
// See https://github.com/twbs/bootstrap/issues/29712
|
||||
|
||||
legend {
|
||||
float: left; // 1
|
||||
width: 100%;
|
||||
padding: 0;
|
||||
margin-bottom: $legend-margin-bottom;
|
||||
@include font-size($legend-font-size);
|
||||
font-weight: $legend-font-weight;
|
||||
line-height: inherit;
|
||||
|
||||
+ * {
|
||||
clear: left; // 2
|
||||
}
|
||||
}
|
||||
|
||||
// Fix height of inputs with a type of datetime-local, date, month, week, or time
|
||||
// See https://github.com/twbs/bootstrap/issues/18842
|
||||
|
||||
::-webkit-datetime-edit-fields-wrapper,
|
||||
::-webkit-datetime-edit-text,
|
||||
::-webkit-datetime-edit-minute,
|
||||
::-webkit-datetime-edit-hour-field,
|
||||
::-webkit-datetime-edit-day-field,
|
||||
::-webkit-datetime-edit-month-field,
|
||||
::-webkit-datetime-edit-year-field {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
::-webkit-inner-spin-button {
|
||||
height: auto;
|
||||
}
|
||||
|
||||
// 1. Correct the outline style in Safari.
|
||||
// 2. This overrides the extra rounded corners on search inputs in iOS so that our
|
||||
// `.form-control` class can properly style them. Note that this cannot simply
|
||||
// be added to `.form-control` as it's not specific enough. For details, see
|
||||
// https://github.com/twbs/bootstrap/issues/11586.
|
||||
|
||||
[type="search"] {
|
||||
outline-offset: -2px; // 1
|
||||
-webkit-appearance: textfield; // 2
|
||||
}
|
||||
|
||||
// 1. A few input types should stay LTR
|
||||
// See https://rtlstyling.com/posts/rtl-styling#form-inputs
|
||||
// 2. RTL only output
|
||||
// See https://rtlcss.com/learn/usage-guide/control-directives/#raw
|
||||
|
||||
/* rtl:raw:
|
||||
[type="tel"],
|
||||
[type="url"],
|
||||
[type="email"],
|
||||
[type="number"] {
|
||||
direction: ltr;
|
||||
}
|
||||
*/
|
||||
|
||||
// Remove the inner padding in Chrome and Safari on macOS.
|
||||
|
||||
::-webkit-search-decoration {
|
||||
-webkit-appearance: none;
|
||||
}
|
||||
|
||||
// Remove padding around color pickers in webkit browsers
|
||||
|
||||
::-webkit-color-swatch-wrapper {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
|
||||
// Inherit font family and line height for file input buttons
|
||||
|
||||
::file-selector-button {
|
||||
font: inherit;
|
||||
}
|
||||
|
||||
// 1. Change font properties to `inherit`
|
||||
// 2. Correct the inability to style clickable types in iOS and Safari.
|
||||
|
||||
::-webkit-file-upload-button {
|
||||
font: inherit; // 1
|
||||
-webkit-appearance: button; // 2
|
||||
}
|
||||
|
||||
// Correct element displays
|
||||
|
||||
output {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
// Remove border from iframe
|
||||
|
||||
iframe {
|
||||
border: 0;
|
||||
}
|
||||
|
||||
// Summary
|
||||
//
|
||||
// 1. Add the correct display in all browsers
|
||||
|
||||
summary {
|
||||
display: list-item; // 1
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
|
||||
// Progress
|
||||
//
|
||||
// Add the correct vertical alignment in Chrome, Firefox, and Opera.
|
||||
|
||||
progress {
|
||||
vertical-align: baseline;
|
||||
}
|
||||
|
||||
|
||||
// Hidden attribute
|
||||
//
|
||||
// Always hide an element with the `hidden` HTML attribute.
|
||||
|
||||
[hidden] {
|
||||
display: none !important;
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user