Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[feature] [request] Support for bootstrap's dark mode #159

Open
ferminc opened this issue Aug 10, 2023 · 4 comments
Open

[feature] [request] Support for bootstrap's dark mode #159

ferminc opened this issue Aug 10, 2023 · 4 comments

Comments

@ferminc
Copy link

ferminc commented Aug 10, 2023

Since v5.3 bootstrap now includes a dark color mode, this is what the datepicker looks like when active, it would be great to have support for it

Screenshot (32)

@BSarmady
Copy link

BSarmady commented Sep 14, 2023

I changed the as following, until it worked for me, you'll probably need to change a little bit more since there are still hardcoded colors in css files.

For my modifications, I used bootstrap css variables to replace hardcoded colors; However, since this component does not exactly follow bootstrap css rules (like button hover, selection, focus) the colors are kind of different.

I also added {buttonClass: 'btn btn-secondary'} to options to make header and today buttons look a little more appealing

.datepicker{ width:-moz-min-content; width:min-content; }
.datepicker:not(.active){ display:none; }
.datepicker-dropdown{ position:absolute; z-index:1000; padding-top:4px; }
.datepicker-dropdown.datepicker-orient-top{ padding-top:0; padding-bottom:4px; }
.datepicker-picker{ display:flex; flex-direction:column; border-radius:0.375rem; background-color:var(--bs-secondary-bg); }
.datepicker-dropdown .datepicker-picker{ box-shadow:0 0.5rem 1rem rgba(0, 0, 0, 0.15); }
.datepicker-main{ flex:auto; padding:2px; }
.datepicker-footer{ box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.1); background-color:var(--bs-secondary-bg); }
.datepicker-title{ box-shadow:inset 0 -1px 1px rgba(0, 0, 0, 0.1); background-color:var(--bs-secondary-bg); padding:0.375rem 0.75rem; text-align:center; font-weight:700; }
.datepicker-controls{ display:flex; }
.datepicker-header .datepicker-controls{ padding:2px 2px 0; }
.datepicker-controls .btn{ /*border-color:var(--bs-secondary-color);*/ background-color:var(--bs-btn-bg); }
.datepicker-controls .btn:hover{ border-color:var(--bs-btn-hover-border-color); background-color:var(--bs-btn-hover-bg); color:var(--bs-btn-hover-color); }
.datepicker-controls .btn:focus{ border-color:var(--bs-btn-hover-border-color); box-shadow:var(--bs-btn-focus-box-shadow); background-color:var(--bs-btn-hover-bg); color:var(--bs-btn-hover-color); }
.datepicker-controls .btn:disabled{ border-color:var(--bs-btn-disabled-border-color); background-color:var(--bs-btn-disabled-bg); color:var(--bs-btn-disabled-color); opacity:var(--bs-btn-disabled-opacity); }
.datepicker-controls .btn:not(:disabled):active{ border-color:#d4dae0; background-color:var(--bs-secondary-color); color:var(--bs-btn-color); }
.datepicker-controls .btn:not(:disabled):active:focus{ box-shadow:0 0 0 0.25rem rgba(211, 212, 213, 0.5); }
.datepicker-header .datepicker-controls .btn{ border-color:transparent; font-weight:bold; }
.datepicker-footer .datepicker-controls .btn{ flex:auto; margin:calc(0.375rem - 1px) 0.375rem; border-radius:0.25rem; font-size:0.875rem; }
.datepicker-controls .view-switch{ flex:auto; }
.datepicker-controls .prev-button, .datepicker-controls .next-button{ padding-right:0.375rem; padding-left:0.375rem; flex:0 0 14.2857142857%; }
.datepicker-controls .prev-button.disabled, .datepicker-controls .next-button.disabled{ visibility:hidden; }
.datepicker-view, .datepicker-grid{ display:flex; }
.datepicker-view{ align-items:stretch; width:15.75rem; }
.datepicker-grid{ flex-wrap:wrap; flex:auto; }
.datepicker .days{ display:flex; flex-direction:column; flex:auto; }
.datepicker .days-of-week{ display:flex; }
.datepicker .week-numbers{ display:flex; flex-direction:column; flex:0 0 9.6774193548%; }
.datepicker .weeks{ display:flex; flex-direction:column; align-items:stretch; flex:auto; }
.datepicker span{ display:flex; align-items:center; justify-content:center; border-radius:0.375rem; cursor:default; -webkit-touch-callout:none; -webkit-user-select:none; -moz-user-select:none; user-select:none; }
.datepicker .dow{ height:1.5rem; font-size:0.9375rem; font-weight:700; }
.datepicker .week{ flex:auto; color:#dee2e6; font-size:0.875rem; }
.datepicker-cell, .datepicker .days .dow{ flex-basis:14.2857142857%; }
.datepicker-cell{ height:2.25rem; }
.datepicker-cell:not(.day){ flex-basis:25%; height:4.5rem; }
.datepicker-cell:not(.disabled):hover{ background-color:var(--bs-primary-bg-subtle); cursor:pointer; }
.datepicker-cell.focused:not(.selected){ background-color:var(--bs-secondary-bg); }
.datepicker-cell.selected, .datepicker-cell.selected:hover{ background-color:var(--bs-primary); color:#ffffff; font-weight:600; }
.datepicker-cell.disabled{ color:rgba(33, 37, 41, 0.5); }
.datepicker-cell.prev:not(.disabled), .datepicker-cell.next:not(.disabled){ color:#6c757d; }
.datepicker-cell.prev.selected, .datepicker-cell.next.selected{ color:#e6e6e6; }
.datepicker-cell.highlighted:not(.selected):not(.range):not(.today){ border-radius:0; background-color:var(--bs-secondary-bg); }
.datepicker-cell.highlighted:not(.selected):not(.range):not(.today):not(.disabled):hover{ background-color:var(--bs-primary-bg-subtle); }
.datepicker-cell.highlighted:not(.selected):not(.range):not(.today).focused{ background-color:var(--bs-secondary-bg); }
.datepicker-cell.today:not(.selected){ background-color:var(--bs-primary-bg-subtle); }
.datepicker-cell.today:not(.selected):not(.disabled){ color:var(--bs-primary-text-emphasis); }
.datepicker-cell.today.focused:not(.selected){ background-color:var(--bs-primary-bg-subtle); }
.datepicker-cell.range-end:not(.selected), .datepicker-cell.range-start:not(.selected){ background-color:#6c757d; color:#ffffff; }
.datepicker-cell.range-end.focused:not(.selected), .datepicker-cell.range-start.focused:not(.selected){ background-color:#69727a; }
.datepicker-cell.range-start:not(.range-end){ border-radius:0.375rem 0 0 0.375rem; }
.datepicker-cell.range-end:not(.range-start){ border-radius:0 0.375rem 0.375rem 0; }
.datepicker-cell.range{ border-radius:0; background-color:#e9ecef; }
.datepicker-cell.range:not(.disabled):not(.focused):not(.today):hover{ background-color:var(--bs-primary-bg-subtle); }
.datepicker-cell.range.disabled{ color:#ced4db; }
.datepicker-cell.range.focused{ background-color:var(--bs-secondary-color); }
.datepicker-input.in-edit{ border-color:#73acfe; }
.datepicker-input.in-edit:focus, .datepicker-input.in-edit:active{ box-shadow:0 0 0.25em 0.25em rgba(115, 172, 254, 0.2); }

@fercomunello
Copy link

fercomunello commented Oct 24, 2023

@BSarmady Thanks for the CSS, currently I'm using Bootstrap v.5.3 so I changed the styles a little bit.

import {Datepicker} from "vanillajs-datepicker";

const {locales}: any = Datepicker;

let inputGroups: HTMLElement[] = [];

document.querySelectorAll(`input[data-component="date-picker"]`)
    .forEach(input => {
        new Datepicker(<HTMLElement> input, {
                autohide: true,
                language: locales['pt-BR'] ? 'pt-BR' : 'en',
                buttonClass: 'btn btn-dark',
                clearButton: true,
                todayButton: true,
                todayButtonMode: 1
            }
        )
       if (input.parentElement?.classList.contains('input-group')) {
           inputGroups.push(<HTMLElement>input.parentElement);
       }
    })
;

for (let i = inputGroups.length - 1; i >= 0; i--){
    const span = inputGroups[i].querySelector('span.input-group-text') as HTMLElement;
    const input: HTMLInputElement | null =
        nextOrPreviousSiblingElement(span, 'input');
    if (input) {
        span?.addEventListener('click',
            () => input.dispatchEvent(new Event('focus')));
    }
    inputGroups.pop();
}
.datepicker {
    width: min-content;

    &:not(.active) {
        display: none;
    }

    .days {
        display: flex;
        flex-direction: column;
        flex: auto;
    }

    .days-of-week {
        display: flex;
    }

    .week-numbers {
        display: flex;
        flex-direction: column;
        flex: 0 0 9.6774193548%;
    }

    .weeks {
        display: flex;
        flex-direction: column;
        align-items: stretch;
        flex: auto;
    }

    span {
        display: flex;
        align-items: center;
        justify-content: center;
        border-radius: 0.375rem;
        cursor: default;
        user-select: none;
    }

    .dow {
        height: 1.5rem;
        font-size: 0.9375rem;
        font-weight: 700;
    }

    .week {
        flex: auto;
        color: #dee2e6;
        font-size: 0.875rem;
    }
}

.datepicker-dropdown {
    position: absolute;
    z-index: var(--z-index-date-picker);
    padding-top: 4px;

    &.datepicker-orient-top {
        padding-top: 0;
        padding-bottom: 4px;
    }

    .datepicker-picker {
        box-shadow: 0 0.5rem 1rem 4px rgba(0, 0, 0, 0.15);
    }
}

.datepicker-picker {
    display: flex;
    flex-direction: column;
    border-radius: 0.375rem;
    background-color: var(--bs-secondary-bg);
}

.datepicker-main {
    flex: auto;
    padding: 2px;
}

.datepicker-footer {
    box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.1);
    background-color: var(--bs-secondary-bg);

    .datepicker-controls {
        .btn {
            flex: auto;
            margin: calc(0.375rem - 1px) 0.375rem;
            border-radius: 0.25rem;
            font-size: 0.875rem;
            font-weight: bold;
        }
    }
}

.datepicker-title {
    box-shadow: inset 0 -1px 1px rgba(0, 0, 0, 0.1);
    background-color: var(--bs-secondary-bg);
    padding: 0.375rem 0.75rem;
    text-align: center;
    font-weight: 700;
}

.datepicker-controls {
    display: flex;
    gap: 4px;

    .btn {
        background-color: var(--bs-btn-bg);

        &:hover {
            border-color: var(--bs-btn-hover-border-color);
            background-color: var(--bs-btn-hover-bg);
            color: var(--bs-btn-hover-color);
        }

        &:focus {
            border-color: var(--bs-btn-hover-border-color);
            box-shadow: var(--bs-btn-focus-box-shadow);
            background-color: var(--bs-btn-hover-bg);
            color: var(--bs-btn-hover-color);
        }

        &:disabled {
            border-color: var(--bs-btn-disabled-border-color);
            background-color: var(--bs-btn-disabled-bg);
            color: var(--bs-btn-disabled-color);
            opacity: var(--bs-btn-disabled-opacity);
        }

        &:not(:disabled):active {
            background-color: var(--bs-btn-hover-bg);
            color: var(--bs-btn-color);

            &:focus {
                box-shadow: 0 0 0 0.25rem rgba(211, 212, 213, 0.5);
            }
        }
    }

    .view-switch {
        flex: auto;
    }
}

.datepicker-header {
    .datepicker-controls {
        padding: 2px 2px 0;

        .btn {
            border-color: transparent;
            font-weight: bold;
        }
    }
}

.datepicker-controls .prev-button,
.datepicker-controls .next-button {
    padding-right: 0.375rem;
    padding-left: 0.375rem;
    flex: 0 0 14.2857142857%;
}

.datepicker-controls .prev-button.disabled,
.datepicker-controls .next-button.disabled {
    visibility: hidden;
}

.datepicker-view, .datepicker-grid {
    display: flex;
}

.datepicker-view {
    align-items: stretch;
    width: 15.75rem;
}

.datepicker-grid {
    flex-wrap: wrap;
    flex: auto;
}

.datepicker-cell, .datepicker .days .dow {
    flex-basis: 14.2857142857%;
}

.datepicker-cell {
    height: 2.25rem;

    &:not(.day) {
        flex-basis: 25%;
        height: 4.5rem;
    }

    &:not(.disabled):hover {
        cursor: pointer;
        [data-bs-theme=auto] &,
        [data-bs-theme=light] & {
            background-color: #dedede;
        }

        [data-bs-theme=dark] & {
            background: var(--bs-tertiary-bg);
        }
    }

    &.focused {
        &:not(.selected) {
            background-color: var(--bs-secondary-bg);
        }
    }

    &.disabled {
        color: rgba(33, 37, 41, 0.5);
    }

    &.highlighted {
        &:not(.selected):not(.range):not(.today) {
            border-radius: 0;
            background-color: var(--bs-secondary-bg);
        }

        &:not(.selected):not(.range):not(.today):not(.disabled):hover {
            background-color: var(--bs-primary-bg-subtle);
        }

        &:not(.selected):not(.range):not(.today).focused {
            background-color: var(--bs-secondary-bg);
        }
    }

    &.today {
        &:not(.selected) {
            background-color: var(--bs-primary-bg-subtle);
        }

        &:not(.selected):not(.disabled) {
            color: var(--bs-primary-text-emphasis);
        }

        &.focused {
            &:not(.selected) {
                background-color: var(--bs-primary-bg-subtle);
            }
        }
    }

    &.range-start {
        &:not(.range-end) {
            border-radius: 0.375rem 0 0 0.375rem;
        }
    }

    &.range-end {
        &:not(.range-start) {
            border-radius: 0 0.375rem 0.375rem 0;
        }
    }

    &.range {
        border-radius: 0;
        background-color: #e9ecef;

        &:not(.disabled):not(.focused):not(.today):hover {
            background-color: var(--bs-primary-bg-subtle);
        }

        &.disabled {
            color: #ced4db;
        }

        &.focused {
            background-color: var(--bs-secondary-color);
        }
    }
}

.datepicker-cell.selected,
.datepicker-cell.selected:hover {
    background-color: var(--bs-primary);
    color: #ffffff;
    font-weight: 600;
}

.datepicker-cell.prev:not(.disabled),
.datepicker-cell.next:not(.disabled) {
    color: #6c757d;
}

.datepicker-cell.prev.selected,
.datepicker-cell.next.selected {
    color: #e6e6e6;
}

.datepicker-cell.range-end:not(.selected),
.datepicker-cell.range-start:not(.selected) {
    background-color: #6c757d;
    color: #ffffff;
}

.datepicker-cell.range-end.focused:not(.selected),
.datepicker-cell.range-start.focused:not(.selected) {
    background-color: #69727a;
}

.datepicker-input {
    &.in-edit {
        border-color: #73acfe;
    }
}

.datepicker-input.in-edit:focus,
.datepicker-input.in-edit:active {
    box-shadow: 0 0 0.25em 0.25em rgba(115, 172, 254, 0.2);
}

@BSarmady
Copy link

@fercomunello, your CSS looks better, however I think you have missed a few of the colors for background and box shadow. I think there is a box shadow variable in 5.3.1 too which can be replaced.

For JavaScript I would go with subtle variants of colors or probably secondary instead of dark so change in theme by user does not break the look. Note that not all developers are using default bootstrap colors, in one of my applications by customer request we changed primary color to pink and secondary to chocolate brown

With subtle it look like this in dark mode and light mode

image

image

@fercomunello
Copy link

@BSarmady You're right. In my case it's fine because I don't customized Bootstrap 5 a lot, I see.. 🤔

image image

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants