update bootstrap to version 5 (#158)

* chore: update bootstrap to version 5

* chore: fix lint

* merge master

* update components to use bootstrap 5
This commit is contained in:
Juan Sebastian velez Posada
2024-01-15 08:56:17 -05:00
committed by GitHub
parent ca79adc4e5
commit 3406e1c647
19 changed files with 3469 additions and 3278 deletions

View File

@@ -1,48 +0,0 @@
@import 'node_modules/bootstrap/less/bootstrap';
@import 'node_modules/font-awesome/less/font-awesome';
@import 'bootswatch/paper/bootswatch';
@import 'bootswatch/paper/variables';
@import 'variables';
@import 'partials/_animations';
body {
min-width: 357px;
}
a.navbar-brand {
img {
margin-top: -12px;
float: left;
margin-right: 7px;
}
}
div.container {
margin-top: 20px;
}
canvas#icon {
display: none;
}
div#status {
display: none;
}
[type='text'].border-danger,
.border-danger {
box-shadow: inset 0 -2px 0 @brand-danger;
&:focus {
.box-shadow(inset 0 -2px 0 @brand-danger);
}
}
.space-between {
display: flex;
justify-content: space-between;
}
.align-items-center {
display: flex;
align-items: center;
}

View File

@@ -1,569 +0,0 @@
// Paper 3.3.4
// Bootswatch
// -----------------------------------------------------
@import url('http://fonts.googleapis.com/css?family=Roboto:300,400,500,700');
// Navbar =====================================================================
.navbar {
border: none;
.box-shadow(0 1px 2px rgba(0,0,0,0.3));
&-brand {
font-size: 24px;
}
&-inverse {
.form-control {
color: #fff;
.placeholder(@navbar-inverse-link-color);
&[type='text'] {
.box-shadow(inset 0 -1px 0 @navbar-inverse-link-color);
&:focus {
.box-shadow(inset 0 -2px 0 #fff);
}
}
}
}
&-nav > li > .dropdown-menu {
margin-top: 2px;
}
}
// Buttons ====================================================================
#btn(@class,@bg) {
.btn-@{class} {
background-size: 200%;
background-position: 50%;
&:hover,
&:active:hover,
&:focus {
background-color: darken(@bg, 6%);
}
&:active {
background-color: darken(@bg, 6%);
#gradient > .radial(darken(@bg, 6%) 10%, @bg 11%);;
background-size: 1000%;
.box-shadow(2px 2px 2px rgba(0,0,0,0.3));
}
}
}
#btn(default,@btn-default-bg);
#btn(primary,@btn-primary-bg);
#btn(success,@btn-success-bg);
#btn(info,@btn-info-bg);
#btn(warning,@btn-warning-bg);
#btn(danger,@btn-danger-bg);
.btn {
text-transform: uppercase;
border-right: none;
border-bottom: none;
.box-shadow(1px 1px 2px rgba(0,0,0,0.3));
.transition(all 0.2s);
&-link {
.box-shadow(none);
&:hover,
&:focus {
color: @brand-primary;
text-decoration: none;
}
}
&-default.disabled {
border: 1px solid @btn-default-border;
}
}
.btn-group {
.btn + .btn,
.btn + .btn-group,
.btn-group + .btn,
.btn-group + .btn-group {
margin-left: 0;
}
&-vertical {
> .btn + .btn,
> .btn + .btn-group,
> .btn-group + .btn,
> .btn-group + .btn-group {
margin-top: 0;
}
}
}
// Typography =================================================================
body {
-webkit-font-smoothing: antialiased;
letter-spacing: 0.1px;
text-rendering: optimizeLegibility;
}
p {
margin: 0 0 1em;
}
input,
button {
-webkit-font-smoothing: antialiased;
letter-spacing: 0.1px;
text-rendering: optimizeLegibility;
}
a {
.transition(all 0.2s);
}
// Tables =====================================================================
// Forms ======================================================================
label {
font-weight: normal;
}
textarea,
textarea.form-control,
input.form-control,
input[type='text'],
input[type='password'],
input[type='email'],
input[type='number'],
[type='text'].form-control,
[type='password'].form-control,
[type='email'].form-control,
[type='tel'].form-control,
[contenteditable].form-control {
padding: 0;
border: none;
border-radius: 0;
-webkit-appearance: none;
.box-shadow(inset 0 -1px 0 #ddd);
font-size: 16px;
&:focus {
.box-shadow(inset 0 -2px 0 @brand-primary);
}
&[disabled],
&[readonly] {
.box-shadow(none);
border-bottom: 1px dotted #ddd;
}
&.input {
&-sm {
font-size: @font-size-small;
}
&-lg {
font-size: @font-size-large;
}
}
}
select,
select.form-control {
border: 0;
border-radius: 0;
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
padding-left: 0;
padding-right: 0\9; // remove padding for < ie9 since default arrow can't be removed
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABoAAAAaCAMAAACelLz8AAAAJ1BMVEVmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmaP/QSjAAAADHRSTlMAAgMJC0uWpKa6wMxMdjkoAAAANUlEQVR4AeXJyQEAERAAsNl7Hf3X6xt0QL6JpZWq30pdvdadme+0PMdzvHm8YThHcT1H7K0BtOMDniZhWOgAAAAASUVORK5CYII=);
background-size: 13px;
background-repeat: no-repeat;
background-position: right center;
.box-shadow(inset 0 -1px 0 #ddd);
font-size: 16px;
line-height: 1.5;
&::-ms-expand {
display: none;
}
&.input {
&-sm {
font-size: @font-size-small;
}
&-lg {
font-size: @font-size-large;
}
}
&:focus {
.box-shadow(inset 0 -2px 0 @brand-primary);
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABoAAAAaCAMAAACelLz8AAAAJ1BMVEUhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISF8S9ewAAAADHRSTlMAAgMJC0uWpKa6wMxMdjkoAAAANUlEQVR4AeXJyQEAERAAsNl7Hf3X6xt0QL6JpZWq30pdvdadme+0PMdzvHm8YThHcT1H7K0BtOMDniZhWOgAAAAASUVORK5CYII=);
}
&[multiple] {
background: none;
}
}
.radio,
.radio-inline,
.checkbox,
.checkbox-inline {
label {
padding-left: 25px;
}
input[type='radio'],
input[type='checkbox'] {
margin-left: -25px;
}
}
input[type='radio'],
.radio input[type='radio'],
.radio-inline input[type='radio'] {
position: relative;
margin-top: 5px;
margin-right: 4px;
vertical-align: -4px;
border: none;
background-color: transparent;
-webkit-appearance: none;
appearance: none;
cursor: pointer;
&:focus {
outline: none;
}
&:before,
&:after {
content: '';
display: block;
width: 18px;
height: 18px;
margin-top: -3px;
border-radius: 50%;
.transition(240ms);
}
&:before {
position: absolute;
left: 0;
top: 0;
background-color: @brand-primary;
.scale(0);
}
&:after {
border: 2px solid @gray;
}
&:checked:before {
.scale(0.5);
}
&:disabled:checked:before {
background-color: @gray-light;
}
&:checked:after {
border-color: @brand-primary;
}
&:disabled:after,
&:disabled:checked:after {
border-color: @gray-light;
}
}
input[type='checkbox'],
.checkbox input[type='checkbox'],
.checkbox-inline input[type='checkbox'] {
position: relative;
vertical-align: -4px;
border: none;
-webkit-appearance: none;
appearance: none;
cursor: pointer;
&:focus {
outline: none;
}
&:after {
content: '';
display: block;
width: 18px;
height: 18px;
margin-top: -2px;
margin-right: 5px;
border: 2px solid @gray;
border-radius: 2px;
.transition(240ms);
}
&:checked:before {
content: '';
position: absolute;
top: 0;
left: 6px;
display: table;
width: 6px;
height: 12px;
border: 2px solid #fff;
border-top-width: 0;
border-left-width: 0;
.rotate(45deg);
}
&:checked:after {
background-color: @brand-primary;
border-color: @brand-primary;
}
&:disabled:after {
border-color: @gray-light;
}
&:disabled:checked:after {
background-color: @gray-light;
border-color: transparent;
}
}
.has-warning {
input:not([type='checkbox']),
.form-control,
input:not([type='checkbox']):focus,
.form-control:focus {
.box-shadow(inset 0 -2px 0 @brand-warning);
}
}
.has-error {
input:not([type='checkbox']),
.form-control,
input:not([type='checkbox']):focus,
.form-control:focus {
.box-shadow(inset 0 -2px 0 @brand-danger);
}
}
.has-success {
input:not([type='checkbox']),
.form-control,
input:not([type='checkbox']):focus,
.form-control:focus {
.box-shadow(inset 0 -2px 0 @brand-success);
}
}
// Navs =======================================================================
.nav-tabs {
> li > a,
> li > a:focus {
margin-right: 0;
background-color: transparent;
border: none;
color: @navbar-default-link-color;
.box-shadow(inset 0 -1px 0 #ddd);
.transition(all 0.2s);
&:hover {
background-color: transparent;
.box-shadow(inset 0 -2px 0 @brand-primary);
color: @brand-primary;
}
}
& > li.active > a,
& > li.active > a:focus {
border: none;
.box-shadow(inset 0 -2px 0 @brand-primary);
color: @brand-primary;
&:hover {
border: none;
color: @brand-primary;
}
}
& > li.disabled > a {
.box-shadow(inset 0 -1px 0 #ddd);
}
&.nav-justified {
& > li > a,
& > li > a:hover,
& > .active > a,
& > .active > a:hover {
border: none;
}
}
.dropdown-menu {
margin-top: 0;
}
}
.dropdown-menu {
border: none;
.box-shadow(0 1px 4px rgba(0,0,0,0.3));
}
// Indicators =================================================================
.alert {
border: none;
color: #fff;
&-success {
background-color: @brand-success;
}
&-info {
background-color: @brand-info;
}
&-warning {
background-color: @brand-warning;
}
&-danger {
background-color: @brand-danger;
}
a:not(.close),
.alert-link {
color: #fff;
font-weight: bold;
}
.close {
color: #fff;
}
}
.badge {
padding: 3px 6px 5px;
}
.progress {
position: relative;
z-index: 1;
height: 6px;
border-radius: 0;
.box-shadow(none);
&-bar {
.box-shadow(none);
&:last-child {
border-radius: 0 3px 3px 0;
}
&:last-child {
&:before {
display: block;
content: '';
position: absolute;
width: 100%;
height: 100%;
left: 0;
right: 0;
z-index: -1;
background-color: lighten(@progress-bar-bg, 35%);
}
}
&-success:last-child.progress-bar:before {
background-color: lighten(@brand-success, 35%);
}
&-info:last-child.progress-bar:before {
background-color: lighten(@brand-info, 45%);
}
&-warning:last-child.progress-bar:before {
background-color: lighten(@brand-warning, 35%);
}
&-danger:last-child.progress-bar:before {
background-color: lighten(@brand-danger, 25%);
}
}
}
// Progress bars ==============================================================
// Containers =================================================================
.close {
font-size: 34px;
font-weight: 300;
line-height: 24px;
opacity: 0.6;
&:hover {
opacity: 1;
}
}
.list-group {
&-item {
padding: 15px;
}
&-item-text {
color: @gray-light;
}
}
.well {
border-radius: 0;
.box-shadow(none);
}
.panel {
border: none;
border-radius: 2px;
.box-shadow(0 1px 4px rgba(0,0,0,0.3));
&-heading {
border-bottom: none;
}
&-footer {
border-top: none;
}
}
.popover {
border: none;
.box-shadow(0 1px 4px rgba(0,0,0,0.3));
}
.carousel {
&-caption {
h1,
h2,
h3,
h4,
h5,
h6 {
color: inherit;
}
}
}

View File

@@ -1,829 +0,0 @@
// Paper 3.3.4
// Variables
// --------------------------------------------------
//== Colors
//
//## Gray and brand colors for use across Bootstrap.
@gray-base: #000;
@gray-darker: lighten(@gray-base, 13.5%); // #222
@gray-dark: #212121;
@gray: #666;
@gray-light: #bbb;
@gray-lighter: lighten(@gray-base, 93.5%); // #eee
@brand-primary: #2196f3;
@brand-success: #4caf50;
@brand-info: #9c27b0;
@brand-warning: #ff9800;
@brand-danger: #e51c23;
//== Scaffolding
//
//## Settings for some of the most global styles.
//** Background color for `<body>`.
@body-bg: #fff;
//** Global text color on `<body>`.
@text-color: @gray;
//** Global textual link color.
@link-color: @brand-primary;
//** Link hover color set via `darken()` function.
@link-hover-color: darken(@link-color, 15%);
//** Link hover decoration.
@link-hover-decoration: underline;
//== Typography
//
//## Font, line-height, and color for body text, headings, and more.
@font-family-sans-serif: 'Roboto', 'Helvetica Neue', Helvetica, Arial, sans-serif;
@font-family-serif: Georgia, 'Times New Roman', Times, serif;
//** Default monospace fonts for `<code>`, `<kbd>`, and `<pre>`.
@font-family-monospace: Menlo, Monaco, Consolas, 'Courier New', monospace;
@font-family-base: @font-family-sans-serif;
@font-size-base: 13px;
@font-size-large: ceil((@font-size-base * 1.25)); // ~18px
@font-size-small: ceil((@font-size-base * 0.85)); // ~12px
@font-size-h1: 56px;
@font-size-h2: 45px;
@font-size-h3: 34px;
@font-size-h4: 24px;
@font-size-h5: 20px;
@font-size-h6: 14px;
//** Unit-less `line-height` for use in components like buttons.
@line-height-base: 1.846; // 20/14
//** Computed "line-height" (`font-size` * `line-height`) for use with `margin`, `padding`, etc.
@line-height-computed: floor((@font-size-base * @line-height-base)); // ~20px
//** By default, this inherits from the `<body>`.
@headings-font-family: inherit;
@headings-font-weight: 400;
@headings-line-height: 1.1;
@headings-color: #444;
//== Iconography
//
//## Specify custom location and filename of the included Glyphicons icon font. Useful for those including Bootstrap via Bower.
//** Load fonts from this directory.
@icon-font-path: '../fonts/';
//** File name for all font files.
@icon-font-name: 'glyphicons-halflings-regular';
//** Element ID within SVG icon file.
@icon-font-svg-id: 'glyphicons_halflingsregular';
//== Components
//
//## Define common padding and border radius sizes and more. Values based on 14px text and 1.428 line-height (~20px to start).
@padding-base-vertical: 6px;
@padding-base-horizontal: 16px;
@padding-large-vertical: 10px;
@padding-large-horizontal: 16px;
@padding-small-vertical: 5px;
@padding-small-horizontal: 10px;
@padding-xs-vertical: 1px;
@padding-xs-horizontal: 5px;
@line-height-large: 1.3333333; // extra decimals for Win 8.1 Chrome
@line-height-small: 1.5;
@border-radius-base: 3px;
@border-radius-large: 3px;
@border-radius-small: 3px;
//** Global color for active items (e.g., navs or dropdowns).
@component-active-color: #fff;
//** Global background color for active items (e.g., navs or dropdowns).
@component-active-bg: @brand-primary;
//** Width of the `border` for generating carets that indicator dropdowns.
@caret-width-base: 4px;
//** Carets increase slightly in size for larger components.
@caret-width-large: 5px;
//== Tables
//
//## Customizes the `.table` component with basic values, each used across all table variations.
//** Padding for `<th>`s and `<td>`s.
@table-cell-padding: 8px;
//** Padding for cells in `.table-condensed`.
@table-condensed-cell-padding: 5px;
//** Default background color used for all tables.
@table-bg: transparent;
//** Background color used for `.table-striped`.
@table-bg-accent: #f9f9f9;
//** Background color used for `.table-hover`.
@table-bg-hover: #f5f5f5;
@table-bg-active: @table-bg-hover;
//** Border color for table and cell borders.
@table-border-color: #ddd;
//== Buttons
//
//## For each of Bootstrap's buttons, define text, background and border color.
@btn-font-weight: normal;
@btn-default-color: @text-color;
@btn-default-bg: #fff;
@btn-default-border: #eee;
@btn-primary-color: #fff;
@btn-primary-bg: @brand-primary;
@btn-primary-border: transparent;
@btn-success-color: #fff;
@btn-success-bg: @brand-success;
@btn-success-border: transparent;
@btn-info-color: #fff;
@btn-info-bg: @brand-info;
@btn-info-border: transparent;
@btn-warning-color: #fff;
@btn-warning-bg: @brand-warning;
@btn-warning-border: transparent;
@btn-danger-color: #fff;
@btn-danger-bg: @brand-danger;
@btn-danger-border: transparent;
@btn-link-disabled-color: @gray-light;
//== Forms
//
//##
//** `<input>` background color
@input-bg: transparent;
//** `<input disabled>` background color
@input-bg-disabled: transparent;
//** Text color for `<input>`s
@input-color: @gray;
//** `<input>` border color
@input-border: transparent;
// TODO: Rename `@input-border-radius` to `@input-border-radius-base` in v4
//** Default `.form-control` border radius
// This has no effect on `<select>`s in some browsers, due to the limited stylability of `<select>`s in CSS.
@input-border-radius: @border-radius-base;
//** Large `.form-control` border radius
@input-border-radius-large: @border-radius-large;
//** Small `.form-control` border radius
@input-border-radius-small: @border-radius-small;
//** Border color for inputs on focus
@input-border-focus: #66afe9;
//** Placeholder text color
@input-color-placeholder: @gray-light;
//** Default `.form-control` height
@input-height-base: (@line-height-computed + (@padding-base-vertical * 2) + 2);
//** Large `.form-control` height
@input-height-large: (
ceil(@font-size-large * @line-height-large) + (@padding-large-vertical * 2) + 2
);
//** Small `.form-control` height
@input-height-small: (
floor(@font-size-small * @line-height-small) + (@padding-small-vertical * 2) + 2
);
//** `.form-group` margin
@form-group-margin-bottom: 15px;
@legend-color: @gray-dark;
@legend-border-color: #e5e5e5;
//** Background color for textual input addons
@input-group-addon-bg: transparent;
//** Border color for textual input addons
@input-group-addon-border-color: @input-border;
//** Disabled cursor for form controls and buttons.
@cursor-disabled: not-allowed;
//== Dropdowns
//
//## Dropdown menu container and contents.
//** Background for the dropdown menu.
@dropdown-bg: #fff;
//** Dropdown menu `border-color`.
@dropdown-border: rgba(0, 0, 0, 0.15);
//** Dropdown menu `border-color` **for IE8**.
@dropdown-fallback-border: #ccc;
//** Divider color for between dropdown items.
@dropdown-divider-bg: #e5e5e5;
//** Dropdown link text color.
@dropdown-link-color: @text-color;
//** Hover color for dropdown links.
@dropdown-link-hover-color: darken(@gray-dark, 5%);
//** Hover background for dropdown links.
@dropdown-link-hover-bg: @gray-lighter;
//** Active dropdown menu item text color.
@dropdown-link-active-color: @component-active-color;
//** Active dropdown menu item background color.
@dropdown-link-active-bg: @component-active-bg;
//** Disabled dropdown menu item background color.
@dropdown-link-disabled-color: @gray-light;
//** Text color for headers within dropdown menus.
@dropdown-header-color: @gray-light;
//** Deprecated `@dropdown-caret-color` as of v3.1.0
@dropdown-caret-color: @gray-light;
//-- Z-index master list
//
// Warning: Avoid customizing these values. They're used for a bird's eye view
// of components dependent on the z-axis and are designed to all work together.
//
// Note: These variables are not generated into the Customizer.
@zindex-navbar: 1000;
@zindex-dropdown: 1000;
@zindex-popover: 1060;
@zindex-tooltip: 1070;
@zindex-navbar-fixed: 1030;
@zindex-modal-background: 1040;
@zindex-modal: 1050;
//== Media queries breakpoints
//
//## Define the breakpoints at which your layout will change, adapting to different screen sizes.
// Extra small screen / phone
//** Deprecated `@screen-xs` as of v3.0.1
@screen-xs: 480px;
//** Deprecated `@screen-xs-min` as of v3.2.0
@screen-xs-min: @screen-xs;
//** Deprecated `@screen-phone` as of v3.0.1
@screen-phone: @screen-xs-min;
// Small screen / tablet
//** Deprecated `@screen-sm` as of v3.0.1
@screen-sm: 768px;
@screen-sm-min: @screen-sm;
//** Deprecated `@screen-tablet` as of v3.0.1
@screen-tablet: @screen-sm-min;
// Medium screen / desktop
//** Deprecated `@screen-md` as of v3.0.1
@screen-md: 992px;
@screen-md-min: @screen-md;
//** Deprecated `@screen-desktop` as of v3.0.1
@screen-desktop: @screen-md-min;
// Large screen / wide desktop
//** Deprecated `@screen-lg` as of v3.0.1
@screen-lg: 1200px;
@screen-lg-min: @screen-lg;
//** Deprecated `@screen-lg-desktop` as of v3.0.1
@screen-lg-desktop: @screen-lg-min;
// So media queries don't overlap when required, provide a maximum
@screen-xs-max: (@screen-sm-min - 1);
@screen-sm-max: (@screen-md-min - 1);
@screen-md-max: (@screen-lg-min - 1);
//== Grid system
//
//## Define your custom responsive grid.
//** Number of columns in the grid.
@grid-columns: 12;
//** Padding between columns. Gets divided in half for the left and right.
@grid-gutter-width: 30px;
// Navbar collapse
//** Point at which the navbar becomes uncollapsed.
@grid-float-breakpoint: @screen-sm-min;
//** Point at which the navbar begins collapsing.
@grid-float-breakpoint-max: (@grid-float-breakpoint - 1);
//== Container sizes
//
//## Define the maximum width of `.container` for different screen sizes.
// Small screen / tablet
@container-tablet: (720px + @grid-gutter-width);
//** For `@screen-sm-min` and up.
@container-sm: @container-tablet;
// Medium screen / desktop
@container-desktop: (940px + @grid-gutter-width);
//** For `@screen-md-min` and up.
@container-md: @container-desktop;
// Large screen / wide desktop
@container-large-desktop: (1140px + @grid-gutter-width);
//** For `@screen-lg-min` and up.
@container-lg: @container-large-desktop;
//== Navbar
//
//##
// Basics of a navbar
@navbar-height: 64px;
@navbar-margin-bottom: @line-height-computed;
@navbar-border-radius: @border-radius-base;
@navbar-padding-horizontal: floor((@grid-gutter-width / 2));
@navbar-padding-vertical: ((@navbar-height - @line-height-computed) / 2);
@navbar-collapse-max-height: 340px;
@navbar-default-color: @gray-light;
@navbar-default-bg: #fff;
@navbar-default-border: transparent;
// Navbar links
@navbar-default-link-color: @gray;
@navbar-default-link-hover-color: @gray-dark;
@navbar-default-link-hover-bg: transparent;
@navbar-default-link-active-color: @gray-dark;
@navbar-default-link-active-bg: darken(@navbar-default-bg, 6.5%);
@navbar-default-link-disabled-color: #ccc;
@navbar-default-link-disabled-bg: transparent;
// Navbar brand label
@navbar-default-brand-color: @navbar-default-link-color;
@navbar-default-brand-hover-color: @navbar-default-link-hover-color;
@navbar-default-brand-hover-bg: transparent;
// Navbar toggle
@navbar-default-toggle-hover-bg: transparent;
@navbar-default-toggle-icon-bar-bg: rgba(0, 0, 0, 0.5);
@navbar-default-toggle-border-color: transparent;
// Inverted navbar
// Reset inverted navbar basics
@navbar-inverse-color: @gray-light;
@navbar-inverse-bg: @brand-primary;
@navbar-inverse-border: transparent;
// Inverted navbar links
@navbar-inverse-link-color: lighten(@brand-primary, 30%);
@navbar-inverse-link-hover-color: #fff;
@navbar-inverse-link-hover-bg: transparent;
@navbar-inverse-link-active-color: @navbar-inverse-link-hover-color;
@navbar-inverse-link-active-bg: darken(@navbar-inverse-bg, 10%);
@navbar-inverse-link-disabled-color: #444;
@navbar-inverse-link-disabled-bg: transparent;
// Inverted navbar brand label
@navbar-inverse-brand-color: @navbar-inverse-link-color;
@navbar-inverse-brand-hover-color: #fff;
@navbar-inverse-brand-hover-bg: transparent;
// Inverted navbar toggle\
@navbar-inverse-toggle-hover-bg: transparent;
@navbar-inverse-toggle-icon-bar-bg: rgba(0, 0, 0, 0.5);
@navbar-inverse-toggle-border-color: transparent;
//== Navs
//
//##
//=== Shared nav styles
@nav-link-padding: 10px 15px;
@nav-link-hover-bg: @gray-lighter;
@nav-disabled-link-color: @gray-light;
@nav-disabled-link-hover-color: @gray-light;
//== Tabs
@nav-tabs-border-color: transparent;
@nav-tabs-link-hover-border-color: @gray-lighter;
@nav-tabs-active-link-hover-bg: transparent;
@nav-tabs-active-link-hover-color: @gray;
@nav-tabs-active-link-hover-border-color: transparent;
@nav-tabs-justified-link-border-color: @nav-tabs-border-color;
@nav-tabs-justified-active-link-border-color: @body-bg;
//== Pills
@nav-pills-border-radius: @border-radius-base;
@nav-pills-active-link-hover-bg: @component-active-bg;
@nav-pills-active-link-hover-color: @component-active-color;
//== Pagination
//
//##
@pagination-color: @link-color;
@pagination-bg: #fff;
@pagination-border: #ddd;
@pagination-hover-color: @link-hover-color;
@pagination-hover-bg: @gray-lighter;
@pagination-hover-border: #ddd;
@pagination-active-color: #fff;
@pagination-active-bg: @brand-primary;
@pagination-active-border: @brand-primary;
@pagination-disabled-color: @gray-light;
@pagination-disabled-bg: #fff;
@pagination-disabled-border: #ddd;
//== Pager
//
//##
@pager-bg: @pagination-bg;
@pager-border: @pagination-border;
@pager-border-radius: 15px;
@pager-hover-bg: @pagination-hover-bg;
@pager-active-bg: @pagination-active-bg;
@pager-active-color: @pagination-active-color;
@pager-disabled-color: @pagination-disabled-color;
//== Jumbotron
//
//##
@jumbotron-padding: 30px;
@jumbotron-color: inherit;
@jumbotron-bg: #f9f9f9;
@jumbotron-heading-color: @headings-color;
@jumbotron-font-size: ceil((@font-size-base * 1.5));
//== Form states and alerts
//
//## Define colors for form feedback states and, by default, alerts.
@state-success-text: @brand-success;
@state-success-bg: #dff0d8;
@state-success-border: darken(spin(@state-success-bg, -10), 5%);
@state-info-text: @brand-info;
@state-info-bg: #e1bee7;
@state-info-border: darken(spin(@state-info-bg, -10), 7%);
@state-warning-text: @brand-warning;
@state-warning-bg: #ffe0b2;
@state-warning-border: darken(spin(@state-warning-bg, -10), 5%);
@state-danger-text: @brand-danger;
@state-danger-bg: #f9bdbb;
@state-danger-border: darken(spin(@state-danger-bg, -10), 5%);
//== Tooltips
//
//##
//** Tooltip max width
@tooltip-max-width: 200px;
//** Tooltip text color
@tooltip-color: #fff;
//** Tooltip background color
@tooltip-bg: #727272;
@tooltip-opacity: 0.9;
//** Tooltip arrow width
@tooltip-arrow-width: 5px;
//** Tooltip arrow color
@tooltip-arrow-color: @tooltip-bg;
//== Popovers
//
//##
//** Popover body background color
@popover-bg: #fff;
//** Popover maximum width
@popover-max-width: 276px;
//** Popover border color
@popover-border-color: transparent;
//** Popover fallback border color
@popover-fallback-border-color: transparent;
//** Popover title background color
@popover-title-bg: darken(@popover-bg, 3%);
//** Popover arrow width
@popover-arrow-width: 10px;
//** Popover arrow color
@popover-arrow-color: @popover-bg;
//** Popover outer arrow width
@popover-arrow-outer-width: (@popover-arrow-width + 1);
//** Popover outer arrow color
@popover-arrow-outer-color: fadein(@popover-border-color, 7.5%);
//** Popover outer arrow fallback color
@popover-arrow-outer-fallback-color: darken(@popover-fallback-border-color, 20%);
//== Labels
//
//##
//** Default label background color
@label-default-bg: @gray-light;
//** Primary label background color
@label-primary-bg: @brand-primary;
//** Success label background color
@label-success-bg: @brand-success;
//** Info label background color
@label-info-bg: @brand-info;
//** Warning label background color
@label-warning-bg: @brand-warning;
//** Danger label background color
@label-danger-bg: @brand-danger;
//** Default label text color
@label-color: #fff;
//** Default text color of a linked label
@label-link-hover-color: #fff;
//== Modals
//
//##
//** Padding applied to the modal body
@modal-inner-padding: 15px;
//** Padding applied to the modal title
@modal-title-padding: 15px;
//** Modal title line-height
@modal-title-line-height: @line-height-base;
//** Background color of modal content area
@modal-content-bg: #fff;
//** Modal content border color
@modal-content-border-color: transparent;
//** Modal content border color **for IE8**
@modal-content-fallback-border-color: #999;
//** Modal backdrop background color
@modal-backdrop-bg: #000;
//** Modal backdrop opacity
@modal-backdrop-opacity: 0.5;
//** Modal header border color
@modal-header-border-color: transparent;
//** Modal footer border color
@modal-footer-border-color: @modal-header-border-color;
@modal-lg: 900px;
@modal-md: 600px;
@modal-sm: 300px;
//== Alerts
//
//## Define alert colors, border radius, and padding.
@alert-padding: 15px;
@alert-border-radius: @border-radius-base;
@alert-link-font-weight: bold;
@alert-success-bg: @state-success-bg;
@alert-success-text: @state-success-text;
@alert-success-border: @state-success-border;
@alert-info-bg: @state-info-bg;
@alert-info-text: @state-info-text;
@alert-info-border: @state-info-border;
@alert-warning-bg: @state-warning-bg;
@alert-warning-text: @state-warning-text;
@alert-warning-border: @state-warning-border;
@alert-danger-bg: @state-danger-bg;
@alert-danger-text: @state-danger-text;
@alert-danger-border: @state-danger-border;
//== Progress bars
//
//##
//** Background color of the whole progress component
@progress-bg: #f5f5f5;
//** Progress bar text color
@progress-bar-color: #fff;
//** Variable for setting rounded corners on progress bar.
@progress-border-radius: @border-radius-base;
//** Default progress bar color
@progress-bar-bg: @brand-primary;
//** Success progress bar color
@progress-bar-success-bg: @brand-success;
//** Warning progress bar color
@progress-bar-warning-bg: @brand-warning;
//** Danger progress bar color
@progress-bar-danger-bg: @brand-danger;
//** Info progress bar color
@progress-bar-info-bg: @brand-info;
//== List group
//
//##
//** Background color on `.list-group-item`
@list-group-bg: #fff;
//** `.list-group-item` border color
@list-group-border: #ddd;
//** List group border radius
@list-group-border-radius: @border-radius-base;
//** Background color of single list items on hover
@list-group-hover-bg: #f5f5f5;
//** Text color of active list items
@list-group-active-color: @component-active-color;
//** Background color of active list items
@list-group-active-bg: @component-active-bg;
//** Border color of active list elements
@list-group-active-border: @list-group-active-bg;
//** Text color for content within active list items
@list-group-active-text-color: lighten(@list-group-active-bg, 40%);
//** Text color of disabled list items
@list-group-disabled-color: @gray-light;
//** Background color of disabled list items
@list-group-disabled-bg: @gray-lighter;
//** Text color for content within disabled list items
@list-group-disabled-text-color: @list-group-disabled-color;
@list-group-link-color: #555;
@list-group-link-hover-color: @list-group-link-color;
@list-group-link-heading-color: #333;
//== Panels
//
//##
@panel-bg: #fff;
@panel-body-padding: 15px;
@panel-heading-padding: 10px 15px;
@panel-footer-padding: @panel-heading-padding;
@panel-border-radius: @border-radius-base;
//** Border color for elements within panels
@panel-inner-border: #ddd;
@panel-footer-bg: #f5f5f5;
@panel-default-text: @gray-dark;
@panel-default-border: #ddd;
@panel-default-heading-bg: #f5f5f5;
@panel-primary-text: #fff;
@panel-primary-border: @brand-primary;
@panel-primary-heading-bg: @brand-primary;
@panel-success-text: #fff;
@panel-success-border: @state-success-border;
@panel-success-heading-bg: @brand-success;
@panel-info-text: #fff;
@panel-info-border: @state-info-border;
@panel-info-heading-bg: @brand-info;
@panel-warning-text: #fff;
@panel-warning-border: @state-warning-border;
@panel-warning-heading-bg: @brand-warning;
@panel-danger-text: #fff;
@panel-danger-border: @state-danger-border;
@panel-danger-heading-bg: @brand-danger;
//== Thumbnails
//
//##
//** Padding around the thumbnail image
@thumbnail-padding: 4px;
//** Thumbnail background color
@thumbnail-bg: @body-bg;
//** Thumbnail border color
@thumbnail-border: #ddd;
//** Thumbnail border radius
@thumbnail-border-radius: @border-radius-base;
//** Custom text color for thumbnail captions
@thumbnail-caption-color: @text-color;
//** Padding around the thumbnail caption
@thumbnail-caption-padding: 9px;
//== Wells
//
//##
@well-bg: #f9f9f9;
@well-border: transparent;
//== Badges
//
//##
@badge-color: #fff;
//** Linked badge text color on hover
@badge-link-hover-color: #fff;
@badge-bg: @gray-light;
//** Badge text color in active nav link
@badge-active-color: @link-color;
//** Badge background color in active nav link
@badge-active-bg: #fff;
@badge-font-weight: normal;
@badge-line-height: 1;
@badge-border-radius: 10px;
//== Breadcrumbs
//
//##
@breadcrumb-padding-vertical: 8px;
@breadcrumb-padding-horizontal: 15px;
//** Breadcrumb background color
@breadcrumb-bg: #f5f5f5;
//** Breadcrumb text color
@breadcrumb-color: #ccc;
//** Text color of current page in the breadcrumb
@breadcrumb-active-color: @gray-light;
//** Textual separator for between breadcrumb elements
@breadcrumb-separator: '/';
//== Carousel
//
//##
@carousel-text-shadow: 0 1px 2px rgba(0, 0, 0, 0.6);
@carousel-control-color: #fff;
@carousel-control-width: 15%;
@carousel-control-opacity: 0.5;
@carousel-control-font-size: 20px;
@carousel-indicator-active-bg: #fff;
@carousel-indicator-border-color: #fff;
@carousel-caption-color: #fff;
//== Close
//
//##
@close-font-weight: normal;
@close-color: #000;
@close-text-shadow: none;
//== Code
//
//##
@code-color: #c7254e;
@code-bg: #f9f2f4;
@kbd-color: #fff;
@kbd-bg: #333;
@pre-bg: #f5f5f5;
@pre-color: @gray-dark;
@pre-border-color: #ccc;
@pre-scrollable-max-height: 340px;
//== Type
//
//##
//** Horizontal offset for forms and lists.
@component-offset-horizontal: 180px;
//** Text muted color
@text-muted: @gray-light;
//** Abbreviations and acronyms border color
@abbr-border-color: @gray-light;
//** Headings small color
@headings-small-color: @gray-light;
//** Blockquote small color
@blockquote-small-color: @gray-light;
//** Blockquote font size
@blockquote-font-size: (@font-size-base * 1.25);
//** Blockquote border color
@blockquote-border-color: @gray-lighter;
//** Page header border color
@page-header-border-color: @gray-lighter;
//** Width of horizontal description list titles
@dl-horizontal-offset: @component-offset-horizontal;
//** Horizontal line color.
@hr-border: @gray-lighter;

View File

@@ -1,14 +0,0 @@
::-webkit-scrollbar {
height: 12px;
width: 12px;
background: @body-bg;
}
::-webkit-scrollbar-thumb {
background: @brand-primary;
-webkit-border-radius: 0;
}
::-webkit-scrollbar-corner {
background: #000;
}

View File

@@ -1,2 +0,0 @@
@navbar-margin-bottom: 0px;
@navbar-border-radius: 0px;

51
assets/sass/app.scss Normal file
View File

@@ -0,0 +1,51 @@
@import 'node_modules/bootswatch/dist/materia/_variables';
@import 'node_modules/bootstrap/scss/bootstrap';
@import 'node_modules/bootswatch/dist/materia/_bootswatch';
@import 'node_modules/font-awesome/scss/font-awesome';
@import 'variables';
@import 'partials/_animations';
body {
min-width: 357px;
}
a.navbar-brand {
display: flex;
align-items: flex-end;
height: 60px;
img {
margin-top: -12px;
margin-right: 7px;
}
}
div.container {
margin-top: 20px;
}
canvas#icon {
display: none;
}
div#status {
display: none;
}
// [type='text'].border-danger,
// .border-danger {
// box-shadow: inset 0 -2px 0 red;
// &:focus {
// .box-shadow(inset 0 -2px 0 #F3F4F5);
// }
// }
.space-between {
display: flex;
justify-content: space-between;
}
.align-items-center {
display: flex;
align-items: center;
}

View File

@@ -0,0 +1,2 @@
$navbar-margin-bottom: 0px;
$navbar-border-radius: 0px;

4604
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -30,7 +30,8 @@
"dependencies": {
"@manaflair/redux-batch": "^1.0.0",
"@reduxjs/toolkit": "^1.9.0",
"bootstrap": "3.4.1",
"bootstrap": "^5.3.2",
"bootswatch": "^5.2.3",
"classnames": "^2.3.2",
"create-react-class": "^15.7.0",
"font-awesome": "4.7.0",
@@ -53,6 +54,7 @@
"@testing-library/jest-dom": "^5.16.5",
"@testing-library/react": "^13.4.0",
"@testing-library/user-event": "^12.6.0",
"@types/bootstrap": "^5.2.10",
"@types/chai": "^4.3.4",
"@types/chrome": "0.0.128",
"@types/classnames": "^2.2.11",
@@ -97,11 +99,11 @@
"jsdom": "^21.0.0",
"jshint": "^2.13.6",
"jsxhint": "^0.15.1",
"less": "^4.1.3",
"lint-staged": "^13.1.0",
"mocha": "^10.2.0",
"mocha-sinon": "^2.1.2",
"node-gyp": "^8.3.0",
"node-sass": "^8.0.0",
"prettier": "^2.8.2",
"prettier-plugin-packagejson": "^2.3.0",
"prettier-plugin-sort-json": "1.0.0",
@@ -115,7 +117,7 @@
"ts-node": "^10.9.1",
"typescript": "^4.9.4",
"wait-on": "^7.0.1",
"web-ext": "^7.4.0",
"web-ext": "^7.10.0",
"webpack": "^5.75.0",
"webpack-cli": "^5.0.1"
}

View File

@@ -30,22 +30,22 @@ describe('MainList', () => {
class="list-group"
>
<a
class="list-group-item"
class="list-group-item text-body-secondary"
href="#"
>
<i
class="fa fa-fw fa-cogs"
class="fa fa-fw fa-cogs me-2"
/>
Options
</a>
<a
class="list-group-item"
class="list-group-item text-body-secondary"
href="https://wakatime.com/login"
rel="noreferrer"
target="_blank"
>
<i
class="fa fa-fw fa-sign-in"
class="fa fa-fw fa-sign-in me-2"
/>
Login
</a>

View File

@@ -1,10 +1,10 @@
import React from 'react';
import { useSelector, useDispatch } from 'react-redux';
import changeExtensionState from '../utils/changeExtensionState';
import { useDispatch, useSelector } from 'react-redux';
import { configLogout, setLoggingEnabled } from '../reducers/configReducer';
import { userLogout } from '../reducers/currentUser';
import { ReduxSelector } from '../types/store';
import { User } from '../types/user';
import changeExtensionState from '../utils/changeExtensionState';
export interface MainListProps {
loggingEnabled: boolean;
@@ -51,7 +51,7 @@ export default function MainList({
<blockquote>
<p>{totalTimeLoggedToday}</p>
<small>
<cite>TOTAL TIME LOGGED TODAY</cite>
<cite className="text-body-secondary">TOTAL TIME LOGGED TODAY</cite>
</small>
</blockquote>
</div>
@@ -61,7 +61,11 @@ export default function MainList({
<div className="row">
<div className="col-xs-12">
<p>
<a href="#" onClick={disableLogging} className="btn btn-danger btn-block">
<a
href="#"
onClick={disableLogging}
className="btn btn-danger btn-block w-100 btn-sm"
>
Disable logging
</a>
</p>
@@ -72,7 +76,11 @@ export default function MainList({
<div className="row">
<div className="col-xs-12">
<p>
<a href="#" onClick={enableLogging} className="btn btn-success btn-block">
<a
href="#"
onClick={enableLogging}
className="btn btn-success btn-block w-100 btn-sm"
>
Enable logging
</a>
</p>
@@ -80,14 +88,14 @@ export default function MainList({
</div>
)}
<div className="list-group">
<a href="#" className="list-group-item" onClick={openOptionsPage}>
<i className="fa fa-fw fa-cogs"></i>
<a href="#" className="list-group-item text-body-secondary" onClick={openOptionsPage}>
<i className="fa fa-fw fa-cogs me-2"></i>
Options
</a>
{user && (
<div>
<a href="#" className="list-group-item" onClick={logoutUser}>
<i className="fa fa-fw fa-sign-out"></i>
<a href="#" className="list-group-item text-body-secondary" onClick={logoutUser}>
<i className="fa fa-fw fa-sign-out me-2"></i>
Logout
</a>
</div>
@@ -97,9 +105,9 @@ export default function MainList({
target="_blank"
rel="noreferrer"
href="https://wakatime.com/login"
className="list-group-item"
className="list-group-item text-body-secondary"
>
<i className="fa fa-fw fa-sign-in"></i>
<i className="fa fa-fw fa-sign-in me-2"></i>
Login
</a>
)}

View File

@@ -18,19 +18,32 @@ describe('NavBar', () => {
expect(container).toMatchInlineSnapshot(`
<div>
<nav
class="navbar navbar-default"
class="navbar shadow-none"
role="navigation"
>
<div
class="container-fluid"
class="navbar-header d-flex w-100 justify-content-between"
>
<div
class="navbar-header"
<a
class="navbar-brand"
href="https://wakatime.com"
rel="noreferrer"
target="_blank"
>
<img
src="graphics/wakatime-logo-48.png"
/>
<div>
WakaTime
</div>
</a>
<button
class="navbar-toggle collapsed"
data-target="#bs-example-navbar-collapse-1"
data-toggle="collapse"
aria-controls="userInfoCollapse"
aria-expanded="false"
aria-label="Toggle navigation"
class="navbar-toggler"
data-bs-target="#userInfoCollapse"
data-bs-toggle="collapse"
type="button"
>
<span
@@ -42,25 +55,14 @@ describe('NavBar', () => {
class="fa fa-fw fa-cogs"
/>
</button>
<a
class="navbar-brand"
href="https://wakatime.com"
rel="noreferrer"
target="_blank"
>
WakaTime
<img
src="graphics/wakatime-logo-48.png"
/>
</a>
</div>
<div
class="collapse navbar-collapse"
id="bs-example-navbar-collapse-1"
class="collapse navbar-collapse mt-4"
id="userInfoCollapse"
>
<div />
<ul
class="nav navbar-nav"
class="nav navbar-nav border-bottom pb-2"
>
<div />
<div />
@@ -69,13 +71,13 @@ describe('NavBar', () => {
>
<a
aria-expanded="false"
class="dropdown-toggle"
data-toggle="dropdown"
class="dropdown-toggle text-body-secondary link-underline link-underline-opacity-0 d-flex w-100 align-items-center"
data-bs-toggle="dropdown"
href="#"
role="button"
>
<i
class="fa fa-fw fa-info"
class="fa fa-fw fa-info me-2"
/>
About
<span
@@ -83,29 +85,35 @@ describe('NavBar', () => {
/>
</a>
<ul
class="dropdown-menu"
class="dropdown-menu shadow-none ms-4"
role="menu"
>
<li>
<li
class="mb-2"
>
<a
class="text-body-secondary link-underline link-underline-opacity-0 d-flex w-100 align-items-center"
href="https://github.com/wakatime/chrome-wakatime/issues"
rel="noreferrer"
target="_blank"
>
<i
class="fa fa-fw fa-bug"
class="fa fa-fw fa-bug me-2"
/>
Report an Issue
</a>
</li>
<li>
<li
class="mb-2"
>
<a
class="text-body-secondary link-underline link-underline-opacity-0 d-flex w-100 align-items-center"
href="https://github.com/wakatime/chrome-wakatime"
rel="noreferrer"
target="_blank"
>
<i
class="fa fa-fw fa-github"
class="fa fa-fw fa-github me-2"
/>
View on GitHub
</a>
@@ -114,7 +122,6 @@ describe('NavBar', () => {
</li>
</ul>
</div>
</div>
</nav>
</div>
`);

View File

@@ -11,7 +11,7 @@ export default function NavBar(): JSX.Element {
const signedInAs = () => {
if (user) {
return (
<p className="navbar-text">
<p className="text-secondary">
Signed in as <b>{user.full_name}</b>
</p>
);
@@ -23,9 +23,14 @@ export default function NavBar(): JSX.Element {
const customRules = () => {
if (user) {
return (
<li>
<a target="_blank" href="https://wakatime.com/settings/rules" rel="noreferrer">
<i className="fa fa-fw fa-filter"></i>
<li className="mb-2">
<a
target="_blank"
href="https://wakatime.com/settings/rules"
rel="noreferrer"
className="text-body-secondary link-underline link-underline-opacity-0 d-flex w-100 align-items-center"
>
<i className="fa fa-fw fa-filter me-2"></i>
Custom Rules
</a>
</li>
@@ -38,9 +43,14 @@ export default function NavBar(): JSX.Element {
const dashboard = () => {
if (user) {
return (
<li>
<a target="_blank" href="https://wakatime.com/dashboard" rel="noreferrer">
<i className="fa fa-fw fa-tachometer"></i>
<li className="mb-2">
<a
target="_blank"
href="https://wakatime.com/dashboard"
rel="noreferrer"
className="text-body-secondary link-underline link-underline-opacity-0 d-flex w-100 align-items-center"
>
<i className="fa fa-fw fa-tachometer me-2"></i>
Dashboard
</a>
</li>
@@ -51,58 +61,63 @@ export default function NavBar(): JSX.Element {
};
return (
<nav className="navbar navbar-default" role="navigation">
<div className="container-fluid">
<div className="navbar-header">
<nav className="navbar shadow-none" role="navigation">
<div className="navbar-header d-flex w-100 justify-content-between">
<a target="_blank" className="navbar-brand" href="https://wakatime.com" rel="noreferrer">
<img src="graphics/wakatime-logo-48.png" />
<div>WakaTime</div>
</a>
<button
className="navbar-toggler"
type="button"
className="navbar-toggle collapsed"
data-toggle="collapse"
data-target="#bs-example-navbar-collapse-1"
data-bs-toggle="collapse"
data-bs-target="#userInfoCollapse"
aria-controls="userInfoCollapse"
aria-expanded="false"
aria-label="Toggle navigation"
>
<span className="sr-only">Toggle navigation</span>
<i className="fa fa-fw fa-cogs"></i>
</button>
<a target="_blank" className="navbar-brand" href="https://wakatime.com" rel="noreferrer">
WakaTime
<img src="graphics/wakatime-logo-48.png" />
</a>
</div>
<div className="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
<div className="collapse navbar-collapse mt-4" id="userInfoCollapse">
{signedInAs()}
<ul className="nav navbar-nav">
<ul className="nav navbar-nav border-bottom pb-2">
{customRules()}
{dashboard()}
<li className="dropdown">
<a
href="#"
className="dropdown-toggle"
data-toggle="dropdown"
className="dropdown-toggle text-body-secondary link-underline link-underline-opacity-0 d-flex w-100 align-items-center"
data-bs-toggle="dropdown"
role="button"
aria-expanded="false"
>
<i className="fa fa-fw fa-info"></i>
<i className="fa fa-fw fa-info me-2"></i>
About
<span className="caret"></span>
</a>
<ul className="dropdown-menu" role="menu">
<li>
<ul className="dropdown-menu shadow-none ms-4" role="menu">
<li className="mb-2">
<a
target="_blank"
href="https://github.com/wakatime/chrome-wakatime/issues"
rel="noreferrer"
className="text-body-secondary link-underline link-underline-opacity-0 d-flex w-100 align-items-center"
>
<i className="fa fa-fw fa-bug"></i>
<i className="fa fa-fw fa-bug me-2"></i>
Report an Issue
</a>
</li>
<li>
<li className="mb-2">
<a
target="_blank"
href="https://github.com/wakatime/chrome-wakatime"
rel="noreferrer"
className="text-body-secondary link-underline link-underline-opacity-0 d-flex w-100 align-items-center"
>
<i className="fa fa-fw fa-github"></i>
<i className="fa fa-fw fa-github me-2"></i>
View on GitHub
</a>
</li>
@@ -110,7 +125,6 @@ export default function NavBar(): JSX.Element {
</li>
</ul>
</div>
</div>
</nav>
);
}

View File

@@ -1,8 +1,9 @@
import { Toast } from 'bootstrap';
import classNames from 'classnames';
import React, { useEffect, useRef, useState } from 'react';
import config, { SuccessOrFailType } from '../config/config';
import apiKeyInvalid from '../utils/apiKey';
import { logUserIn } from '../utils/user';
import Alert from './Alert';
import SitesList from './SitesList';
interface State {
@@ -11,7 +12,6 @@ interface State {
apiKey: string;
apiUrl: string;
blacklist: string;
displayAlert: boolean;
hostname: string;
loading: boolean;
loggingStyle: string;
@@ -28,7 +28,6 @@ export default function Options(): JSX.Element {
apiKey: '',
apiUrl: config.apiUrl,
blacklist: '',
displayAlert: false,
hostname: '',
loading: false,
loggingStyle: config.loggingStyle,
@@ -39,6 +38,8 @@ export default function Options(): JSX.Element {
whitelist: '',
});
const liveToastRef = useRef(null);
const loggingStyleRef = useRef(null);
const restoreSettings = async (): Promise<void> => {
@@ -82,14 +83,6 @@ export default function Options(): JSX.Element {
void restoreSettings();
}, []);
useEffect(() => {
if (state.displayAlert) {
setTimeout(function () {
setState({ ...state, displayAlert: false, loading: false });
}, 2500);
}
}, [state.displayAlert]);
const handleSubmit = async () => {
if (state.loading) return;
setState({ ...state, loading: true });
@@ -130,7 +123,6 @@ export default function Options(): JSX.Element {
apiKey,
apiUrl,
blacklist,
displayAlert: true,
hostname,
loggingStyle,
loggingType,
@@ -139,6 +131,8 @@ export default function Options(): JSX.Element {
trackSocialMedia,
whitelist,
});
// eslint-disable-next-line
Toast.getOrCreateInstance(liveToastRef?.current ?? '')?.show();
await logUserIn(state.apiKey);
};
@@ -183,20 +177,6 @@ export default function Options(): JSX.Element {
);
};
const alert = () => {
return (
<div
style={{
height: state.displayAlert ? 55 : 0,
opacity: state.displayAlert ? 1 : 0,
transition: 'opacity 500ms, height 1000ms',
}}
>
<Alert key={state.alertText} type={state.alertType} text={state.alertText} />
</div>
);
};
const isApiKeyValid = apiKeyInvalid(state.apiKey) === '';
return (
@@ -211,29 +191,28 @@ export default function Options(): JSX.Element {
>
<div className="row">
<div className="col-md-12">
{alert()}
<form className="form-horizontal">
<div className="form-group">
<label className="col-lg-2 control-label">API Key</label>
<div className="col-lg-10">
<div className="form-group mb-4">
<label htmlFor="apiKey" className="form-label mb-0">
API Key
</label>
<input
id="apiKey"
autoFocus={true}
type="text"
className={`form-control ${isApiKeyValid ? '' : 'border-danger'}`}
className={`form-control ${isApiKeyValid ? '' : 'is-invalid'}`}
placeholder="API key"
value={state.apiKey}
onChange={(e) => setState({ ...state, apiKey: e.target.value })}
/>
</div>
</div>
<div className="form-group">
<label className="col-lg-2 control-label">Logging style!</label>
<div className="col-lg-10">
<div className="form-group mb-4">
<label htmlFor="loggingStyle" className="form-label">
Logging style
</label>
<select
id="loggingStyle"
ref={loggingStyleRef}
className="form-control"
value={state.loggingStyle}
@@ -243,15 +222,15 @@ export default function Options(): JSX.Element {
<option value="whitelist">Only whitelisted sites</option>
</select>
</div>
</div>
{loggingStyle()}
<div className="form-group">
<label className="col-lg-2 control-label">Logging type</label>
<div className="col-lg-10">
<div className="form-group mb-4">
<label htmlFor="loggingType" className="form-label">
Logging type
</label>
<select
id="loggingType"
className="form-control"
value={state.loggingType}
onChange={(e) => setState({ ...state, loggingType: e.target.value })}
@@ -260,15 +239,13 @@ export default function Options(): JSX.Element {
<option value="url">Entire URL</option>
</select>
</div>
</div>
<div className="form-group">
<label htmlFor="theme" className="col-lg-2 control-label">
<div className="form-group mb-4">
<label htmlFor="selectTheme" className="form-label mb-0">
Theme
</label>
<div className="col-lg-10">
<select
id="selectTheme"
className="form-control"
value={state.theme}
onChange={(e) => setState({ ...state, theme: e.target.value })}
@@ -277,33 +254,30 @@ export default function Options(): JSX.Element {
<option value="dark">Dark</option>
</select>
</div>
</div>
<div className="form-group">
<label htmlFor="theme" className="col-lg-2 control-label">
<div className="form-group mb-4">
<label htmlFor="selectHost" className="form-label mb-0">
Hostname
</label>
<div className="col-lg-10">
<input
id="selectHost"
type="text"
className="form-control"
value={state.hostname}
onChange={(e) => setState({ ...state, hostname: e.target.value })}
/>
<span className="help-block">
<span className="text-secondary">
Optional name of local machine. By default &apos;Unknown Hostname&apos;.
</span>
</div>
</div>
<div className="form-group">
<label htmlFor="theme" className="col-lg-2 control-label">
<div className="form-group mb-4">
<label htmlFor="apiUrl" className="form-label mb-0">
API Url
</label>
<div className="col-lg-10">
<input
id="apiUrl"
type="text"
className="form-control"
value={state.apiUrl}
@@ -312,13 +286,13 @@ export default function Options(): JSX.Element {
/>
<span className="help-block">https://api.wakatime.com/api/v1</span>
</div>
</div>
<div className="form-group row">
<div className="form-group row mb-4">
<div className="col-lg-10 col-lg-offset-2 space-between align-items-center">
<div>
<input
type="checkbox"
className="me-2"
checked={state.trackSocialMedia}
onChange={toggleSocialMedia}
/>
@@ -327,8 +301,8 @@ export default function Options(): JSX.Element {
<button
type="button"
className="btn btn-primary btn-sm"
data-toggle="modal"
data-target="#socialSitesModal"
data-bs-toggle="modal"
data-bs-target="#socialSitesModal"
>
Sites
</button>
@@ -341,17 +315,15 @@ export default function Options(): JSX.Element {
<div className="modal-dialog" role="document">
<div className="modal-content">
<div className="modal-header">
<button
type="button"
className="close"
data-dismiss="modal"
aria-label="Close"
>
<span aria-hidden="true">&times;</span>
</button>
<h4 className="modal-title" id="socialSitesModalLabel">
<h4 className="modal-title fs-5" id="socialSitesModalLabel">
Social Media Sites
</h4>
<button
type="button"
className="btn-close"
data-bs-dismiss="modal"
aria-label="Close"
></button>
</div>
<div className="modal-body">
<SitesList
@@ -368,7 +340,7 @@ export default function Options(): JSX.Element {
/>
</div>
<div className="modal-footer">
<button type="button" className="btn btn-primary" data-dismiss="modal">
<button type="button" className="btn btn-primary" data-bs-dismiss="modal">
Close
</button>
</div>
@@ -378,8 +350,8 @@ export default function Options(): JSX.Element {
</div>
</div>
<div className="form-group">
<div className="col-lg-10 col-lg-offset-2">
<div className="form-group mb-4">
<div className="d-grid gap-2 col-6 ">
<button
type="button"
className={`btn btn-primary ${state.loading ? 'disabled' : ''}`}
@@ -391,6 +363,30 @@ export default function Options(): JSX.Element {
</button>
</div>
</div>
<div className="toast-container position-fixed bottom-0 end-0 p-3">
<div
className={classNames(
'toast align-items-center justify-content-between alert',
`alert-${state.alertType}`,
)}
role="alert"
aria-live="assertive"
aria-atomic="true"
id="liveToast"
ref={liveToastRef}
data-bs-delay="3000"
>
<div className="fs-5">{state.alertText}</div>
<div data-bs-theme="dark">
<button
type="button"
className="btn-close m-0"
data-bs-dismiss="toast"
aria-label="Close"
></button>
</div>
</div>
</div>
</form>
</div>
</div>

View File

@@ -22,20 +22,21 @@ export default function SitesList({
};
return (
<div className="form-group">
<label htmlFor="sites" className="col-lg-2 control-label">
<div className="form-group mb-4">
<label htmlFor={`${label}-siteList`} className="col-lg-2 control-label">
{label}
</label>
<div className="col-lg-10">
<textarea
id={`${label}-siteList`}
className="form-control"
rows={rows ?? 3}
onChange={textareaChange}
placeholder={placeholder ?? 'http://google.com'}
value={sites}
></textarea>
<span className="help-block">
<span className="text-secondary">
{helpText}
<br />
One line per site.

View File

@@ -30,7 +30,7 @@ export default function WakaTime(): JSX.Element {
const isApiKeyValid = apiKeyInvalid(apiKeyFromRedux) === '';
return (
<div>
<div className="py-4 px-2 pt-0">
<NavBar />
{isApiKeyValid && extensionState === 'notSignedIn' && (
<Alert
@@ -48,7 +48,7 @@ export default function WakaTime(): JSX.Element {
style={{ cursor: 'pointer' }}
/>
)}
<div className="container">
<div className="container mt-0">
<div className="row">
<div className="col-md-12">
<MainList loggingEnabled={loggingEnabled} totalTimeLoggedToday={totalTimeLoggedToday} />

View File

@@ -5,9 +5,7 @@ import WakaTime from './components/WakaTime';
import createStore from './stores/createStore';
import checkCurrentUser from './utils/checkCurrentUser';
/* This is a fix for Bootstrap requiring jQuery */
global.jQuery = require('jquery');
require('bootstrap');
import 'bootstrap/dist/js/bootstrap';
const container = document.getElementById('wakatime');
const root = createRoot(container!);

View File

@@ -82,11 +82,11 @@ load({
'clean:webpack': exec('rimraf dist'),
dev: ['clean', 'postinstall', concurrent('watch', 'web-ext:run:firefox', 'web-ext:run:chrome')],
eslint: exec('eslint src . --fix'),
less: exec('lessc assets/less/app.less public/css/app.css'),
lint: ['prettier', 'eslint'],
postinstall: ['clean', makePublicFolder, copyFromNodeModules, 'less'],
postinstall: ['clean', makePublicFolder, copyFromNodeModules, 'sass'],
prettier: [exec('prettier --write .')],
'remotedev-server': exec('remotedev --hostname=localhost --port=8000'),
sass: exec('node-sass assets/sass/app.scss public/css/app.css'),
test: ['build', 'lint', 'test-jest'],
'test-jest': [exec('jest --clearCache'), exec('jest --verbose --coverage')],
watch: concurrent('watch-jest', 'webpack:watch'),