diff --git a/.github/workflows/django.yml b/.github/workflows/django.yml index d64b69b..53b7fbb 100644 --- a/.github/workflows/django.yml +++ b/.github/workflows/django.yml @@ -24,7 +24,7 @@ jobs: with: python-version: 3.11 cache: poetry - - run: poetry install + - run: poetry install - name: Run Tests run: | poetry run python manage.py test diff --git a/approval_polls/settings.py b/approval_polls/settings.py index c3a3e13..dd23380 100644 --- a/approval_polls/settings.py +++ b/approval_polls/settings.py @@ -1,4 +1,5 @@ import os +import sys import environ import sentry_sdk @@ -27,6 +28,15 @@ if DEBUG: db_path = os.path.join(BASE_DIR, "db.sqlite3") +if not DEBUG: + COMPRESS_OFFLINE = True + LIBSASS_OUTPUT_STYLE = "compressed" + +if "test" in sys.argv: + COMPRESS_OFFLINE = False + COMPRESS_ENABLED = False + + DATABASES = { "default": { # Add 'postgresql_psycopg2', 'mysql', 'sqlite3' or 'oracle'. @@ -97,6 +107,14 @@ # Example: "http://example.com/static/", "http://static.example.com/" STATIC_URL = "/static/" +COMPRESS_PRECOMPILERS = (("text/x-scss", "django_libsass.SassCompiler"),) + +STATICFILES_FINDERS = [ + "django.contrib.staticfiles.finders.FileSystemFinder", + "django.contrib.staticfiles.finders.AppDirectoriesFinder", + "compressor.finders.CompressorFinder", +] + # Additional locations of static files STATICFILES_DIRS = ( os.path.join(BASE_DIR, "staticfiles/"), @@ -105,12 +123,6 @@ # Don't forget to use absolute paths, not relative paths. ) -# List of finder classes that know how to find static files in -# various locations. -STATICFILES_FINDERS = ( - "django.contrib.staticfiles.finders.FileSystemFinder", - "django.contrib.staticfiles.finders.AppDirectoriesFinder", -) STORAGES = { "default": { @@ -180,6 +192,7 @@ "allauth.socialaccount.providers.google", "widget_tweaks", "import_export", + "compressor", ) ACCOUNT_ACTIVATION_DAYS = 7 diff --git a/approval_polls/staticfiles/scss/bootstrap/_accordion.scss b/approval_polls/staticfiles/scss/bootstrap/_accordion.scss new file mode 100644 index 0000000..133bf5a --- /dev/null +++ b/approval_polls/staticfiles/scss/bootstrap/_accordion.scss @@ -0,0 +1,173 @@ +// +// Base styles +// + +.accordion { + // scss-docs-start accordion-css-vars + --#{$prefix}accordion-color: #{$accordion-color}; + --#{$prefix}accordion-bg: #{$accordion-bg}; + --#{$prefix}accordion-transition: #{$accordion-transition}; + --#{$prefix}accordion-border-color: #{$accordion-border-color}; + --#{$prefix}accordion-border-width: #{$accordion-border-width}; + --#{$prefix}accordion-border-radius: #{$accordion-border-radius}; + --#{$prefix}accordion-inner-border-radius: #{$accordion-inner-border-radius}; + --#{$prefix}accordion-btn-padding-x: #{$accordion-button-padding-x}; + --#{$prefix}accordion-btn-padding-y: #{$accordion-button-padding-y}; + --#{$prefix}accordion-btn-color: #{$accordion-button-color}; + --#{$prefix}accordion-btn-bg: #{$accordion-button-bg}; + --#{$prefix}accordion-btn-icon: #{escape-svg($accordion-button-icon)}; + --#{$prefix}accordion-btn-icon-width: #{$accordion-icon-width}; + --#{$prefix}accordion-btn-icon-transform: #{$accordion-icon-transform}; + --#{$prefix}accordion-btn-icon-transition: #{$accordion-icon-transition}; + --#{$prefix}accordion-btn-active-icon: #{escape-svg( + $accordion-button-active-icon + )}; + --#{$prefix}accordion-btn-focus-box-shadow: #{$accordion-button-focus-box-shadow}; + --#{$prefix}accordion-body-padding-x: #{$accordion-body-padding-x}; + --#{$prefix}accordion-body-padding-y: #{$accordion-body-padding-y}; + --#{$prefix}accordion-active-color: #{$accordion-button-active-color}; + --#{$prefix}accordion-active-bg: #{$accordion-button-active-bg}; + // scss-docs-end accordion-css-vars +} + +.accordion-button { + position: relative; + display: flex; + align-items: center; + width: 100%; + padding: var(--#{$prefix}accordion-btn-padding-y) + var(--#{$prefix}accordion-btn-padding-x); + @include font-size($font-size-base); + color: var(--#{$prefix}accordion-btn-color); + text-align: left; // Reset button style + background-color: var(--#{$prefix}accordion-btn-bg); + border: 0; + @include border-radius(0); + overflow-anchor: none; + @include transition(var(--#{$prefix}accordion-transition)); + + &:not(.collapsed) { + color: var(--#{$prefix}accordion-active-color); + background-color: var(--#{$prefix}accordion-active-bg); + box-shadow: inset 0 calc(-1 * var(--#{$prefix}accordion-border-width)) 0 + var(--#{$prefix}accordion-border-color); // stylelint-disable-line function-disallowed-list + + &::after { + background-image: var(--#{$prefix}accordion-btn-active-icon); + transform: var(--#{$prefix}accordion-btn-icon-transform); + } + } + + // Accordion icon + &::after { + flex-shrink: 0; + width: var(--#{$prefix}accordion-btn-icon-width); + height: var(--#{$prefix}accordion-btn-icon-width); + margin-left: auto; + content: ""; + background-image: var(--#{$prefix}accordion-btn-icon); + background-repeat: no-repeat; + background-size: var(--#{$prefix}accordion-btn-icon-width); + @include transition(var(--#{$prefix}accordion-btn-icon-transition)); + } + + &:hover { + z-index: 2; + } + + &:focus { + z-index: 3; + outline: 0; + box-shadow: var(--#{$prefix}accordion-btn-focus-box-shadow); + } +} + +.accordion-header { + margin-bottom: 0; +} + +.accordion-item { + color: var(--#{$prefix}accordion-color); + background-color: var(--#{$prefix}accordion-bg); + border: var(--#{$prefix}accordion-border-width) solid + var(--#{$prefix}accordion-border-color); + + &:first-of-type { + @include border-top-radius(var(--#{$prefix}accordion-border-radius)); + + > .accordion-header .accordion-button { + @include border-top-radius( + var(--#{$prefix}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(var(--#{$prefix}accordion-border-radius)); + + > .accordion-header .accordion-button { + &.collapsed { + @include border-bottom-radius( + var(--#{$prefix}accordion-inner-border-radius) + ); + } + } + + > .accordion-collapse { + @include border-bottom-radius(var(--#{$prefix}accordion-border-radius)); + } + } +} + +.accordion-body { + padding: var(--#{$prefix}accordion-body-padding-y) + var(--#{$prefix}accordion-body-padding-x); +} + +// Flush accordion items +// +// Remove borders and border-radius to keep accordion items edge-to-edge. + +.accordion-flush { + > .accordion-item { + border-right: 0; + border-left: 0; + @include border-radius(0); + + &:first-child { + border-top: 0; + } + &:last-child { + border-bottom: 0; + } + + // stylelint-disable selector-max-class + > .accordion-header .accordion-button { + &, + &.collapsed { + @include border-radius(0); + } + } + // stylelint-enable selector-max-class + + > .accordion-collapse { + @include border-radius(0); + } + } +} + +@if $enable-dark-mode { + @include color-mode(dark) { + .accordion-button::after { + --#{$prefix}accordion-btn-icon: #{escape-svg($accordion-button-icon-dark)}; + --#{$prefix}accordion-btn-active-icon: #{escape-svg( + $accordion-button-active-icon-dark + )}; + } + } +} diff --git a/approval_polls/staticfiles/scss/bootstrap/_alert.scss b/approval_polls/staticfiles/scss/bootstrap/_alert.scss new file mode 100644 index 0000000..20df5ce --- /dev/null +++ b/approval_polls/staticfiles/scss/bootstrap/_alert.scss @@ -0,0 +1,66 @@ +// +// Base styles +// + +.alert { + // scss-docs-start alert-css-vars + --#{$prefix}alert-bg: transparent; + --#{$prefix}alert-padding-x: #{$alert-padding-x}; + --#{$prefix}alert-padding-y: #{$alert-padding-y}; + --#{$prefix}alert-margin-bottom: #{$alert-margin-bottom}; + --#{$prefix}alert-color: inherit; + --#{$prefix}alert-border-color: transparent; + --#{$prefix}alert-border: #{$alert-border-width} solid var(--#{$prefix}alert-border-color); + --#{$prefix}alert-border-radius: #{$alert-border-radius}; + --#{$prefix}alert-link-color: inherit; + // scss-docs-end alert-css-vars + + position: relative; + padding: var(--#{$prefix}alert-padding-y) var(--#{$prefix}alert-padding-x); + margin-bottom: var(--#{$prefix}alert-margin-bottom); + color: var(--#{$prefix}alert-color); + background-color: var(--#{$prefix}alert-bg); + border: var(--#{$prefix}alert-border); + @include border-radius(var(--#{$prefix}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; + color: var(--#{$prefix}alert-link-color); +} + +// 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 in map-keys($theme-colors) { + .alert-#{$state} { + --#{$prefix}alert-color: var(--#{$prefix}#{$state}-text-emphasis); + --#{$prefix}alert-bg: var(--#{$prefix}#{$state}-bg-subtle); + --#{$prefix}alert-border-color: var(--#{$prefix}#{$state}-border-subtle); + --#{$prefix}alert-link-color: var(--#{$prefix}#{$state}-text-emphasis); + } +} +// scss-docs-end alert-modifiers diff --git a/approval_polls/staticfiles/scss/bootstrap/_badge.scss b/approval_polls/staticfiles/scss/bootstrap/_badge.scss new file mode 100644 index 0000000..cc3d269 --- /dev/null +++ b/approval_polls/staticfiles/scss/bootstrap/_badge.scss @@ -0,0 +1,38 @@ +// Base class +// +// Requires one of the contextual, color modifier classes for `color` and +// `background-color`. + +.badge { + // scss-docs-start badge-css-vars + --#{$prefix}badge-padding-x: #{$badge-padding-x}; + --#{$prefix}badge-padding-y: #{$badge-padding-y}; + @include rfs($badge-font-size, --#{$prefix}badge-font-size); + --#{$prefix}badge-font-weight: #{$badge-font-weight}; + --#{$prefix}badge-color: #{$badge-color}; + --#{$prefix}badge-border-radius: #{$badge-border-radius}; + // scss-docs-end badge-css-vars + + display: inline-block; + padding: var(--#{$prefix}badge-padding-y) var(--#{$prefix}badge-padding-x); + @include font-size(var(--#{$prefix}badge-font-size)); + font-weight: var(--#{$prefix}badge-font-weight); + line-height: 1; + color: var(--#{$prefix}badge-color); + text-align: center; + white-space: nowrap; + vertical-align: baseline; + @include border-radius(var(--#{$prefix}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; +} diff --git a/approval_polls/staticfiles/scss/bootstrap/_breadcrumb.scss b/approval_polls/staticfiles/scss/bootstrap/_breadcrumb.scss new file mode 100644 index 0000000..40a866d --- /dev/null +++ b/approval_polls/staticfiles/scss/bootstrap/_breadcrumb.scss @@ -0,0 +1,48 @@ +.breadcrumb { + // scss-docs-start breadcrumb-css-vars + --#{$prefix}breadcrumb-padding-x: #{$breadcrumb-padding-x}; + --#{$prefix}breadcrumb-padding-y: #{$breadcrumb-padding-y}; + --#{$prefix}breadcrumb-margin-bottom: #{$breadcrumb-margin-bottom}; + @include rfs($breadcrumb-font-size, --#{$prefix}breadcrumb-font-size); + --#{$prefix}breadcrumb-bg: #{$breadcrumb-bg}; + --#{$prefix}breadcrumb-border-radius: #{$breadcrumb-border-radius}; + --#{$prefix}breadcrumb-divider-color: #{$breadcrumb-divider-color}; + --#{$prefix}breadcrumb-item-padding-x: #{$breadcrumb-item-padding-x}; + --#{$prefix}breadcrumb-item-active-color: #{$breadcrumb-active-color}; + // scss-docs-end breadcrumb-css-vars + + display: flex; + flex-wrap: wrap; + padding: var(--#{$prefix}breadcrumb-padding-y) + var(--#{$prefix}breadcrumb-padding-x); + margin-bottom: var(--#{$prefix}breadcrumb-margin-bottom); + @include font-size(var(--#{$prefix}breadcrumb-font-size)); + list-style: none; + background-color: var(--#{$prefix}breadcrumb-bg); + @include border-radius(var(--#{$prefix}breadcrumb-border-radius)); +} + +.breadcrumb-item { + // The separator between breadcrumbs (by default, a forward-slash: "/") + + .breadcrumb-item { + padding-left: var(--#{$prefix}breadcrumb-item-padding-x); + + &::before { + float: left; // Suppress inline spacings and underlining of the separator + padding-right: var(--#{$prefix}breadcrumb-item-padding-x); + color: var(--#{$prefix}breadcrumb-divider-color); + content: var( + --#{$prefix}breadcrumb-divider, + escape-svg($breadcrumb-divider) + ) + #{"/* rtl:"} var( + --#{$prefix}breadcrumb-divider, + escape-svg($breadcrumb-divider-flipped) + ) #{"*/"}; + } + } + + &.active { + color: var(--#{$prefix}breadcrumb-item-active-color); + } +} diff --git a/approval_polls/staticfiles/scss/bootstrap/_button-group.scss b/approval_polls/staticfiles/scss/bootstrap/_button-group.scss new file mode 100644 index 0000000..edf243d --- /dev/null +++ b/approval_polls/staticfiles/scss/bootstrap/_button-group.scss @@ -0,0 +1,147 @@ +// 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 { + @include border-radius($btn-border-radius); + + // Prevent double borders when buttons are next to each other + > :not(.btn-check:first-child) + .btn, + > .btn-group:not(:first-child) { + margin-left: calc( + #{$btn-border-width} * -1 + ); // stylelint-disable-line function-disallowed-list + } + + // Reset rounded corners + > .btn:not(:last-child):not(.dropdown-toggle), + > .btn.dropdown-toggle-split:first-child, + > .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 * 0.75; + padding-left: $btn-padding-x * 0.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 * 0.75; + padding-left: $btn-padding-x-sm * 0.75; +} + +.btn-lg + .dropdown-toggle-split { + padding-right: $btn-padding-x-lg * 0.75; + padding-left: $btn-padding-x-lg * 0.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: calc( + #{$btn-border-width} * -1 + ); // stylelint-disable-line function-disallowed-list + } + + // 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); + } +} diff --git a/approval_polls/staticfiles/scss/bootstrap/_buttons.scss b/approval_polls/staticfiles/scss/bootstrap/_buttons.scss new file mode 100644 index 0000000..3484514 --- /dev/null +++ b/approval_polls/staticfiles/scss/bootstrap/_buttons.scss @@ -0,0 +1,228 @@ +// +// Base styles +// + +.btn { + // scss-docs-start btn-css-vars + --#{$prefix}btn-padding-x: #{$btn-padding-x}; + --#{$prefix}btn-padding-y: #{$btn-padding-y}; + --#{$prefix}btn-font-family: #{$btn-font-family}; + @include rfs($btn-font-size, --#{$prefix}btn-font-size); + --#{$prefix}btn-font-weight: #{$btn-font-weight}; + --#{$prefix}btn-line-height: #{$btn-line-height}; + --#{$prefix}btn-color: #{$btn-color}; + --#{$prefix}btn-bg: transparent; + --#{$prefix}btn-border-width: #{$btn-border-width}; + --#{$prefix}btn-border-color: transparent; + --#{$prefix}btn-border-radius: #{$btn-border-radius}; + --#{$prefix}btn-hover-border-color: transparent; + --#{$prefix}btn-box-shadow: #{$btn-box-shadow}; + --#{$prefix}btn-disabled-opacity: #{$btn-disabled-opacity}; + --#{$prefix}btn-focus-box-shadow: 0 0 0 #{$btn-focus-width} rgba(var(--#{$prefix}btn-focus-shadow-rgb), 0.5); + // scss-docs-end btn-css-vars + + display: inline-block; + padding: var(--#{$prefix}btn-padding-y) var(--#{$prefix}btn-padding-x); + font-family: var(--#{$prefix}btn-font-family); + @include font-size(var(--#{$prefix}btn-font-size)); + font-weight: var(--#{$prefix}btn-font-weight); + line-height: var(--#{$prefix}btn-line-height); + color: var(--#{$prefix}btn-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; + border: var(--#{$prefix}btn-border-width) solid + var(--#{$prefix}btn-border-color); + @include border-radius(var(--#{$prefix}btn-border-radius)); + @include gradient-bg(var(--#{$prefix}btn-bg)); + @include box-shadow(var(--#{$prefix}btn-box-shadow)); + @include transition($btn-transition); + + &:hover { + color: var(--#{$prefix}btn-hover-color); + text-decoration: if($link-hover-decoration == underline, none, null); + background-color: var(--#{$prefix}btn-hover-bg); + border-color: var(--#{$prefix}btn-hover-border-color); + } + + .btn-check + &:hover { + // override for the checkbox/radio buttons + color: var(--#{$prefix}btn-color); + background-color: var(--#{$prefix}btn-bg); + border-color: var(--#{$prefix}btn-border-color); + } + + &:focus-visible { + color: var(--#{$prefix}btn-hover-color); + @include gradient-bg(var(--#{$prefix}btn-hover-bg)); + border-color: var(--#{$prefix}btn-hover-border-color); + outline: 0; + // Avoid using mixin so we can pass custom focus shadow properly + @if $enable-shadows { + box-shadow: var(--#{$prefix}btn-box-shadow), + var(--#{$prefix}btn-focus-box-shadow); + } @else { + box-shadow: var(--#{$prefix}btn-focus-box-shadow); + } + } + + .btn-check:focus-visible + & { + border-color: var(--#{$prefix}btn-hover-border-color); + outline: 0; + // Avoid using mixin so we can pass custom focus shadow properly + @if $enable-shadows { + box-shadow: var(--#{$prefix}btn-box-shadow), + var(--#{$prefix}btn-focus-box-shadow); + } @else { + box-shadow: var(--#{$prefix}btn-focus-box-shadow); + } + } + + .btn-check:checked + &, + :not(.btn-check) + &:active, + &:first-child:active, + &.active, + &.show { + color: var(--#{$prefix}btn-active-color); + background-color: var(--#{$prefix}btn-active-bg); + // Remove CSS gradients if they're enabled + background-image: if($enable-gradients, none, null); + border-color: var(--#{$prefix}btn-active-border-color); + @include box-shadow(var(--#{$prefix}btn-active-shadow)); + + &:focus-visible { + // Avoid using mixin so we can pass custom focus shadow properly + @if $enable-shadows { + box-shadow: var(--#{$prefix}btn-active-shadow), + var(--#{$prefix}btn-focus-box-shadow); + } @else { + box-shadow: var(--#{$prefix}btn-focus-box-shadow); + } + } + } + + .btn-check:checked:focus-visible + & { + // Avoid using mixin so we can pass custom focus shadow properly + @if $enable-shadows { + box-shadow: var(--#{$prefix}btn-active-shadow), + var(--#{$prefix}btn-focus-box-shadow); + } @else { + box-shadow: var(--#{$prefix}btn-focus-box-shadow); + } + } + + &:disabled, + &.disabled, + fieldset:disabled & { + color: var(--#{$prefix}btn-disabled-color); + pointer-events: none; + background-color: var(--#{$prefix}btn-disabled-bg); + background-image: if($enable-gradients, none, null); + border-color: var(--#{$prefix}btn-disabled-border-color); + opacity: var(--#{$prefix}btn-disabled-opacity); + @include box-shadow(none); + } +} + +// +// Alternate buttons +// + +// scss-docs-start btn-variant-loops +@each $color, $value in $theme-colors { + .btn-#{$color} { + @if $color == "light" { + @include button-variant( + $value, + $value, + $hover-background: shade-color($value, $btn-hover-bg-shade-amount), + $hover-border: shade-color($value, $btn-hover-border-shade-amount), + $active-background: shade-color($value, $btn-active-bg-shade-amount), + $active-border: shade-color($value, $btn-active-border-shade-amount) + ); + } @else if $color == "dark" { + @include button-variant( + $value, + $value, + $hover-background: tint-color($value, $btn-hover-bg-tint-amount), + $hover-border: tint-color($value, $btn-hover-border-tint-amount), + $active-background: tint-color($value, $btn-active-bg-tint-amount), + $active-border: tint-color($value, $btn-active-border-tint-amount) + ); + } @else { + @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 { + --#{$prefix}btn-font-weight: #{$font-weight-normal}; + --#{$prefix}btn-color: #{$btn-link-color}; + --#{$prefix}btn-bg: transparent; + --#{$prefix}btn-border-color: transparent; + --#{$prefix}btn-hover-color: #{$btn-link-hover-color}; + --#{$prefix}btn-hover-border-color: transparent; + --#{$prefix}btn-active-color: #{$btn-link-hover-color}; + --#{$prefix}btn-active-border-color: transparent; + --#{$prefix}btn-disabled-color: #{$btn-link-disabled-color}; + --#{$prefix}btn-disabled-border-color: transparent; + --#{$prefix}btn-box-shadow: 0 0 0 #000; // Can't use `none` as keyword negates all values when used with multiple shadows + --#{$prefix}btn-focus-shadow-rgb: #{$btn-link-focus-shadow-rgb}; + + text-decoration: $link-decoration; + @if $enable-gradients { + background-image: none; + } + + &:hover, + &:focus-visible { + text-decoration: $link-hover-decoration; + } + + &:focus-visible { + color: var(--#{$prefix}btn-color); + } + + &:hover { + color: var(--#{$prefix}btn-hover-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 + ); +} diff --git a/approval_polls/staticfiles/scss/bootstrap/_card.scss b/approval_polls/staticfiles/scss/bootstrap/_card.scss new file mode 100644 index 0000000..51b79c5 --- /dev/null +++ b/approval_polls/staticfiles/scss/bootstrap/_card.scss @@ -0,0 +1,260 @@ +// +// Base styles +// + +.card { + // scss-docs-start card-css-vars + --#{$prefix}card-spacer-y: #{$card-spacer-y}; + --#{$prefix}card-spacer-x: #{$card-spacer-x}; + --#{$prefix}card-title-spacer-y: #{$card-title-spacer-y}; + --#{$prefix}card-title-color: #{$card-title-color}; + --#{$prefix}card-subtitle-color: #{$card-subtitle-color}; + --#{$prefix}card-border-width: #{$card-border-width}; + --#{$prefix}card-border-color: #{$card-border-color}; + --#{$prefix}card-border-radius: #{$card-border-radius}; + --#{$prefix}card-box-shadow: #{$card-box-shadow}; + --#{$prefix}card-inner-border-radius: #{$card-inner-border-radius}; + --#{$prefix}card-cap-padding-y: #{$card-cap-padding-y}; + --#{$prefix}card-cap-padding-x: #{$card-cap-padding-x}; + --#{$prefix}card-cap-bg: #{$card-cap-bg}; + --#{$prefix}card-cap-color: #{$card-cap-color}; + --#{$prefix}card-height: #{$card-height}; + --#{$prefix}card-color: #{$card-color}; + --#{$prefix}card-bg: #{$card-bg}; + --#{$prefix}card-img-overlay-padding: #{$card-img-overlay-padding}; + --#{$prefix}card-group-margin: #{$card-group-margin}; + // scss-docs-end card-css-vars + + position: relative; + display: flex; + flex-direction: column; + min-width: 0; // See https://github.com/twbs/bootstrap/pull/22740#issuecomment-305868106 + height: var(--#{$prefix}card-height); + color: var(--#{$prefix}body-color); + word-wrap: break-word; + background-color: var(--#{$prefix}card-bg); + background-clip: border-box; + border: var(--#{$prefix}card-border-width) solid + var(--#{$prefix}card-border-color); + @include border-radius(var(--#{$prefix}card-border-radius)); + @include box-shadow(var(--#{$prefix}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(var(--#{$prefix}card-inner-border-radius)); + } + + &:last-child { + border-bottom-width: 0; + @include border-bottom-radius(var(--#{$prefix}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: var(--#{$prefix}card-spacer-y) var(--#{$prefix}card-spacer-x); + color: var(--#{$prefix}card-color); +} + +.card-title { + margin-bottom: var(--#{$prefix}card-title-spacer-y); + color: var(--#{$prefix}card-title-color); +} + +.card-subtitle { + margin-top: calc( + -0.5 * var(--#{$prefix}card-title-spacer-y) + ); // stylelint-disable-line function-disallowed-list + margin-bottom: 0; + color: var(--#{$prefix}card-subtitle-color); +} + +.card-text:last-child { + margin-bottom: 0; +} + +.card-link { + &:hover { + text-decoration: if($link-hover-decoration == underline, none, null); + } + + + .card-link { + margin-left: var(--#{$prefix}card-spacer-x); + } +} + +// +// Optional textual caps +// + +.card-header { + padding: var(--#{$prefix}card-cap-padding-y) + var(--#{$prefix}card-cap-padding-x); + margin-bottom: 0; // Removes the default margin-bottom of + color: var(--#{$prefix}card-cap-color); + background-color: var(--#{$prefix}card-cap-bg); + border-bottom: var(--#{$prefix}card-border-width) solid + var(--#{$prefix}card-border-color); + + &:first-child { + @include border-radius( + var(--#{$prefix}card-inner-border-radius) + var(--#{$prefix}card-inner-border-radius) 0 0 + ); + } +} + +.card-footer { + padding: var(--#{$prefix}card-cap-padding-y) + var(--#{$prefix}card-cap-padding-x); + color: var(--#{$prefix}card-cap-color); + background-color: var(--#{$prefix}card-cap-bg); + border-top: var(--#{$prefix}card-border-width) solid + var(--#{$prefix}card-border-color); + + &:last-child { + @include border-radius( + 0 0 var(--#{$prefix}card-inner-border-radius) + var(--#{$prefix}card-inner-border-radius) + ); + } +} + +// +// Header navs +// + +.card-header-tabs { + margin-right: calc( + -0.5 * var(--#{$prefix}card-cap-padding-x) + ); // stylelint-disable-line function-disallowed-list + margin-bottom: calc( + -1 * var(--#{$prefix}card-cap-padding-y) + ); // stylelint-disable-line function-disallowed-list + margin-left: calc( + -0.5 * var(--#{$prefix}card-cap-padding-x) + ); // stylelint-disable-line function-disallowed-list + border-bottom: 0; + + .nav-link.active { + background-color: var(--#{$prefix}card-bg); + border-bottom-color: var(--#{$prefix}card-bg); + } +} + +.card-header-pills { + margin-right: calc( + -0.5 * var(--#{$prefix}card-cap-padding-x) + ); // stylelint-disable-line function-disallowed-list + margin-left: calc( + -0.5 * var(--#{$prefix}card-cap-padding-x) + ); // stylelint-disable-line function-disallowed-list +} + +// Card image +.card-img-overlay { + position: absolute; + top: 0; + right: 0; + bottom: 0; + left: 0; + padding: var(--#{$prefix}card-img-overlay-padding); + @include border-radius(var(--#{$prefix}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(var(--#{$prefix}card-inner-border-radius)); +} + +.card-img, +.card-img-bottom { + @include border-bottom-radius(var(--#{$prefix}card-inner-border-radius)); +} + +// +// Card groups +// + +.card-group { + // The child selector allows nested `.card` within `.card-group` + // to display properly. + > .card { + margin-bottom: var(--#{$prefix}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; + } + } + } + } + } +} diff --git a/approval_polls/staticfiles/scss/bootstrap/_carousel.scss b/approval_polls/staticfiles/scss/bootstrap/_carousel.scss new file mode 100644 index 0000000..a4733c1 --- /dev/null +++ b/approval_polls/staticfiles/scss/bootstrap/_carousel.scss @@ -0,0 +1,243 @@ +// 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; +} + +.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%); +} + +// +// 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, 0.25), rgba($black, 0.001)), + null + ); +} +.carousel-control-next { + right: 0; + background-image: if( + $enable-gradients, + linear-gradient(270deg, rgba($black, 0.25), rgba($black, 0.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%; +} + +.carousel-control-prev-icon { + background-image: escape-svg($carousel-control-prev-icon-bg) #{"/*rtl:" + + escape-svg($carousel-control-next-icon-bg) + "*/"}; +} +.carousel-control-next-icon { + background-image: escape-svg($carousel-control-next-icon-bg) #{"/*rtl:" + + escape-svg($carousel-control-prev-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; + + [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) * 0.5; + bottom: $carousel-caption-spacer; + left: (100% - $carousel-caption-width) * 0.5; + padding-top: $carousel-caption-padding-y; + padding-bottom: $carousel-caption-padding-y; + color: $carousel-caption-color; + text-align: center; +} + +// Dark mode carousel + +@mixin 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; + } +} + +.carousel-dark { + @include carousel-dark(); +} + +@if $enable-dark-mode { + @include color-mode(dark) { + @if $color-mode-type == "media-query" { + .carousel { + @include carousel-dark(); + } + } @else { + .carousel, + &.carousel { + @include carousel-dark(); + } + } + } +} diff --git a/approval_polls/staticfiles/scss/bootstrap/_close.scss b/approval_polls/staticfiles/scss/bootstrap/_close.scss new file mode 100644 index 0000000..c410247 --- /dev/null +++ b/approval_polls/staticfiles/scss/bootstrap/_close.scss @@ -0,0 +1,64 @@ +// 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 { + // scss-docs-start close-css-vars + --#{$prefix}btn-close-color: #{$btn-close-color}; + --#{$prefix}btn-close-bg: #{escape-svg($btn-close-bg)}; + --#{$prefix}btn-close-opacity: #{$btn-close-opacity}; + --#{$prefix}btn-close-hover-opacity: #{$btn-close-hover-opacity}; + --#{$prefix}btn-close-focus-shadow: #{$btn-close-focus-shadow}; + --#{$prefix}btn-close-focus-opacity: #{$btn-close-focus-opacity}; + --#{$prefix}btn-close-disabled-opacity: #{$btn-close-disabled-opacity}; + --#{$prefix}btn-close-white-filter: #{$btn-close-white-filter}; + // scss-docs-end close-css-vars + + box-sizing: content-box; + width: $btn-close-width; + height: $btn-close-height; + padding: $btn-close-padding-y $btn-close-padding-x; + color: var(--#{$prefix}btn-close-color); + background: transparent var(--#{$prefix}btn-close-bg) center / + $btn-close-width auto no-repeat; // include transparent for button elements + border: 0; // for button elements + @include border-radius(); + opacity: var(--#{$prefix}btn-close-opacity); + + // Override 's hover style + &:hover { + color: var(--#{$prefix}btn-close-color); + text-decoration: none; + opacity: var(--#{$prefix}btn-close-hover-opacity); + } + + &:focus { + outline: 0; + box-shadow: var(--#{$prefix}btn-close-focus-shadow); + opacity: var(--#{$prefix}btn-close-focus-opacity); + } + + &:disabled, + &.disabled { + pointer-events: none; + user-select: none; + opacity: var(--#{$prefix}btn-close-disabled-opacity); + } +} + +@mixin btn-close-white() { + filter: var(--#{$prefix}btn-close-white-filter); +} + +.btn-close-white { + @include btn-close-white(); +} + +@if $enable-dark-mode { + @include color-mode(dark) { + .btn-close { + @include btn-close-white(); + } + } +} diff --git a/approval_polls/staticfiles/scss/bootstrap/_containers.scss b/approval_polls/staticfiles/scss/bootstrap/_containers.scss new file mode 100644 index 0000000..83b3138 --- /dev/null +++ b/approval_polls/staticfiles/scss/bootstrap/_containers.scss @@ -0,0 +1,41 @@ +// Container widths +// +// Set the container width, and override it for fixed navbars in media queries. + +@if $enable-container-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; + } + } + } + } + } +} diff --git a/approval_polls/staticfiles/scss/bootstrap/_dropdown.scss b/approval_polls/staticfiles/scss/bootstrap/_dropdown.scss new file mode 100644 index 0000000..7cbc2fd --- /dev/null +++ b/approval_polls/staticfiles/scss/bootstrap/_dropdown.scss @@ -0,0 +1,255 @@ +// The dropdown wrapper (`
`) +.dropup, +.dropend, +.dropdown, +.dropstart, +.dropup-center, +.dropdown-center { + position: relative; +} + +.dropdown-toggle { + white-space: nowrap; + + // Generate the caret automatically + @include caret(); +} + +// The dropdown menu +.dropdown-menu { + // scss-docs-start dropdown-css-vars + --#{$prefix}dropdown-zindex: #{$zindex-dropdown}; + --#{$prefix}dropdown-min-width: #{$dropdown-min-width}; + --#{$prefix}dropdown-padding-x: #{$dropdown-padding-x}; + --#{$prefix}dropdown-padding-y: #{$dropdown-padding-y}; + --#{$prefix}dropdown-spacer: #{$dropdown-spacer}; + @include rfs($dropdown-font-size, --#{$prefix}dropdown-font-size); + --#{$prefix}dropdown-color: #{$dropdown-color}; + --#{$prefix}dropdown-bg: #{$dropdown-bg}; + --#{$prefix}dropdown-border-color: #{$dropdown-border-color}; + --#{$prefix}dropdown-border-radius: #{$dropdown-border-radius}; + --#{$prefix}dropdown-border-width: #{$dropdown-border-width}; + --#{$prefix}dropdown-inner-border-radius: #{$dropdown-inner-border-radius}; + --#{$prefix}dropdown-divider-bg: #{$dropdown-divider-bg}; + --#{$prefix}dropdown-divider-margin-y: #{$dropdown-divider-margin-y}; + --#{$prefix}dropdown-box-shadow: #{$dropdown-box-shadow}; + --#{$prefix}dropdown-link-color: #{$dropdown-link-color}; + --#{$prefix}dropdown-link-hover-color: #{$dropdown-link-hover-color}; + --#{$prefix}dropdown-link-hover-bg: #{$dropdown-link-hover-bg}; + --#{$prefix}dropdown-link-active-color: #{$dropdown-link-active-color}; + --#{$prefix}dropdown-link-active-bg: #{$dropdown-link-active-bg}; + --#{$prefix}dropdown-link-disabled-color: #{$dropdown-link-disabled-color}; + --#{$prefix}dropdown-item-padding-x: #{$dropdown-item-padding-x}; + --#{$prefix}dropdown-item-padding-y: #{$dropdown-item-padding-y}; + --#{$prefix}dropdown-header-color: #{$dropdown-header-color}; + --#{$prefix}dropdown-header-padding-x: #{$dropdown-header-padding-x}; + --#{$prefix}dropdown-header-padding-y: #{$dropdown-header-padding-y}; + // scss-docs-end dropdown-css-vars + + position: absolute; + z-index: var(--#{$prefix}dropdown-zindex); + display: none; // none by default, but block on "open" of the menu + min-width: var(--#{$prefix}dropdown-min-width); + padding: var(--#{$prefix}dropdown-padding-y) + var(--#{$prefix}dropdown-padding-x); + margin: 0; // Override default margin of ul + @include font-size(var(--#{$prefix}dropdown-font-size)); + color: var(--#{$prefix}dropdown-color); + text-align: left; // Ensures proper alignment if parent has it changed (e.g., modal footer) + list-style: none; + background-color: var(--#{$prefix}dropdown-bg); + background-clip: padding-box; + border: var(--#{$prefix}dropdown-border-width) solid + var(--#{$prefix}dropdown-border-color); + @include border-radius(var(--#{$prefix}dropdown-border-radius)); + @include box-shadow(var(--#{$prefix}dropdown-box-shadow)); + + &[data-bs-popper] { + top: 100%; + left: 0; + margin-top: var(--#{$prefix}dropdown-spacer); + } + + @if $dropdown-padding-y == 0 { + > .dropdown-item:first-child, + > li:first-child .dropdown-item { + @include border-top-radius(var(--#{$prefix}dropdown-inner-border-radius)); + } + > .dropdown-item:last-child, + > li:last-child .dropdown-item { + @include border-bottom-radius( + var(--#{$prefix}dropdown-inner-border-radius) + ); + } + } +} + +// 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: var(--#{$prefix}dropdown-spacer); + } + + .dropdown-toggle { + @include caret(up); + } +} + +.dropend { + .dropdown-menu[data-bs-popper] { + top: 0; + right: auto; + left: 100%; + margin-top: 0; + margin-left: var(--#{$prefix}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: var(--#{$prefix}dropdown-spacer); + } + + .dropdown-toggle { + @include caret(start); + &::before { + vertical-align: 0; + } + } +} + +// Dividers (basically an `
`) within the dropdown +.dropdown-divider { + height: 0; + margin: var(--#{$prefix}dropdown-divider-margin-y) 0; + overflow: hidden; + border-top: 1px solid var(--#{$prefix}dropdown-divider-bg); + opacity: 1; // Revisit in v6 to de-dupe styles that conflict with
element +} + +// Links, buttons, and more within the dropdown menu +// +// `
- - - +
+
+
+
+ +
+ + +
+ Register +
+
+ - -
- -
- - Sign in with Google - - -
- {% endblock content %} diff --git a/approval_polls/templates/account/signup_closed.html b/approval_polls/templates/account/signup_closed.html index 3fed9f7..3e1badc 100644 --- a/approval_polls/templates/account/signup_closed.html +++ b/approval_polls/templates/account/signup_closed.html @@ -1,8 +1,7 @@ {% extends "base.html" %} {% load i18n %} {% load allauth %} -{% block head_title - %} +{% block head_title %} {% trans "Sign Up Closed" %} {% endblock head_title %} {% block content %} diff --git a/approval_polls/templates/base.html b/approval_polls/templates/base.html index 983ef11..c31a9a5 100644 --- a/approval_polls/templates/base.html +++ b/approval_polls/templates/base.html @@ -27,12 +27,6 @@ - - + {% load compress %} + {% compress css %} + + {% endcompress %} Approval Polls from The Center for Election Science {% block head %} {% endblock head %} @@ -100,10 +101,8 @@
-
- {% block content %} - {% endblock content %} -
+ {% block content %} + {% endblock content %}

diff --git a/approval_polls/templates/index.html b/approval_polls/templates/index.html index 50396e4..3c60509 100644 --- a/approval_polls/templates/index.html +++ b/approval_polls/templates/index.html @@ -7,7 +7,7 @@

Latest Public Polls

{% for poll in latest_poll_list %}
{{ poll.question }} -

Published on {{ poll.pub_date|date:"N j, Y, P e" }} by {{ poll.user.username }}

+

Published on {{ poll.pub_date|date:"N j, Y, P e" }} by {% firstof poll.user.username poll.user.first_name %}

{% endfor %}
diff --git a/approval_polls/templates/results.html b/approval_polls/templates/results.html index ef2b9f3..7c68f90 100644 --- a/approval_polls/templates/results.html +++ b/approval_polls/templates/results.html @@ -7,7 +7,7 @@

{{ poll.question }}

-
+

{{ poll.total_ballots }} @@ -18,7 +18,7 @@

-
+
{% for choice in poll.choice_set.all|sort_by_votes %}

{{ choice.choice_text }} diff --git a/entrypoint.sh b/entrypoint.sh index ffbfccc..cb9a186 100755 --- a/entrypoint.sh +++ b/entrypoint.sh @@ -6,6 +6,7 @@ set -e # Run Django migrations echo "Running migrations" python manage.py migrate --noinput +python manage.py compress python manage.py collectstatic --noinput # Start Gunicorn server diff --git a/poetry.lock b/poetry.lock index 32e21a1..a04322e 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 1.7.0 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.8.3 and should not be changed by hand. [[package]] name = "asgiref" @@ -348,6 +348,37 @@ requests-oauthlib = ">=0.3.0" mfa = ["qrcode (>=7.0.0)"] saml = ["python3-saml (>=1.15.0,<2.0.0)"] +[[package]] +name = "django-appconf" +version = "1.0.6" +description = "A helper class for handling configuration defaults of packaged apps gracefully." +optional = false +python-versions = ">=3.7" +files = [ + {file = "django-appconf-1.0.6.tar.gz", hash = "sha256:cfe87ea827c4ee04b9a70fab90b86d704cb02f2981f89da8423cb0fabf88efbf"}, + {file = "django_appconf-1.0.6-py3-none-any.whl", hash = "sha256:c3ae442fba1ff7ec830412c5184b17169a7a1e71cf0864a4c3f93cf4c98a1993"}, +] + +[package.dependencies] +django = "*" + +[[package]] +name = "django-compressor" +version = "4.5.1" +description = "('Compresses linked and inline JavaScript or CSS into single cached files.',)" +optional = false +python-versions = ">=3.8" +files = [ + {file = "django_compressor-4.5.1-py2.py3-none-any.whl", hash = "sha256:87741edee4e7f24f3e0b8072d94a990cfb010cb2ca7cc443944da8e193cdea65"}, + {file = "django_compressor-4.5.1.tar.gz", hash = "sha256:c1d8a48a2ee4d8b7f23c411eb9c97e2d88db18a18ba1c9e8178d5f5b8366a822"}, +] + +[package.dependencies] +Django = ">=4.2" +django-appconf = ">=1.0.3" +rcssmin = "1.1.2" +rjsmin = "1.2.2" + [[package]] name = "django-environ" version = "0.11.2" @@ -408,6 +439,21 @@ files = [ [package.dependencies] python-ipware = ">=2.0.0" +[[package]] +name = "django-libsass" +version = "0.9" +description = "A django-compressor filter to compile SASS files using libsass" +optional = false +python-versions = "*" +files = [ + {file = "django-libsass-0.9.tar.gz", hash = "sha256:bfbbb55a8950bb40fa04dd416605f92da34ad1f303b10a41abc3232386ec27b5"}, + {file = "django_libsass-0.9-py3-none-any.whl", hash = "sha256:5234d29100889cac79e36a0f44207ec6d275adfd2da1acb6a94b55c89fe2bd97"}, +] + +[package.dependencies] +django-compressor = ">=1.3" +libsass = ">=0.7.0,<1" + [[package]] name = "django-passkeys" version = "1.2.7" @@ -655,6 +701,21 @@ files = [ [package.extras] dev = ["hypothesis"] +[[package]] +name = "libsass" +version = "0.23.0" +description = "Sass for Python: A straightforward binding of libsass for Python." +optional = false +python-versions = ">=3.8" +files = [ + {file = "libsass-0.23.0-cp38-abi3-macosx_11_0_x86_64.whl", hash = "sha256:34cae047cbbfc4ffa832a61cbb110f3c95f5471c6170c842d3fed161e40814dc"}, + {file = "libsass-0.23.0-cp38-abi3-macosx_14_0_arm64.whl", hash = "sha256:ea97d1b45cdc2fc3590cb9d7b60f1d8915d3ce17a98c1f2d4dd47ee0d9c68ce6"}, + {file = "libsass-0.23.0-cp38-abi3-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:4a218406d605f325d234e4678bd57126a66a88841cb95bee2caeafdc6f138306"}, + {file = "libsass-0.23.0-cp38-abi3-win32.whl", hash = "sha256:31e86d92a5c7a551df844b72d83fc2b5e50abc6fbbb31e296f7bebd6489ed1b4"}, + {file = "libsass-0.23.0-cp38-abi3-win_amd64.whl", hash = "sha256:a2ec85d819f353cbe807432d7275d653710d12b08ec7ef61c124a580a8352f3c"}, + {file = "libsass-0.23.0.tar.gz", hash = "sha256:6f209955ede26684e76912caf329f4ccb57e4a043fd77fe0e7348dd9574f1880"}, +] + [[package]] name = "markuppy" version = "1.14" @@ -928,6 +989,62 @@ files = [ {file = "PyYAML-6.0.1.tar.gz", hash = "sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43"}, ] +[[package]] +name = "rcssmin" +version = "1.1.2" +description = "CSS Minifier" +optional = false +python-versions = "*" +files = [ + {file = "rcssmin-1.1.2-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:0101a55992ded00220d38ebaf003d0858c1e6e8b365df6f18f9d7a2cdc5574b3"}, + {file = "rcssmin-1.1.2-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:9d7a5c6a08948ae5d7e1422ac34031fc05242786e6b600b37948412ee16f3655"}, + {file = "rcssmin-1.1.2-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:5f602bcaa457680a89904c10d1a539ffae5d4de08ec61a2044efc93c9a743860"}, + {file = "rcssmin-1.1.2-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:d9384421d8cb516202349da7b6502d77df14860fa710f91dbe0b03b3b895dda3"}, + {file = "rcssmin-1.1.2-cp310-cp310-manylinux1_i686.whl", hash = "sha256:d40964dc7fbd74be30b1ef5543bb75c479a53d53362ecccba3f1a5de6453faca"}, + {file = "rcssmin-1.1.2-cp310-cp310-manylinux1_x86_64.whl", hash = "sha256:c9a55657a3d11c5901259b14f941ed7eec118cd5a4416535102eda491de6753f"}, + {file = "rcssmin-1.1.2-cp310-cp310-manylinux2014_aarch64.whl", hash = "sha256:065b7f85902c87011951b1d084fa694099d70feb6bef1c3e89456a1a0668c73b"}, + {file = "rcssmin-1.1.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:b37db48eacf5b8ad09ee14eb25db8cc7176ce2339c1028499547858c152a936a"}, + {file = "rcssmin-1.1.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:f1468ccbfe16a2b4cff5bc0d330488bb496f71b542d26bd2005b2ab05a295752"}, + {file = "rcssmin-1.1.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:b3577e4955b89324cd8214ae8e9c2ce452197ea2f789527538cf41e662930495"}, + {file = "rcssmin-1.1.2-cp311-cp311-manylinux1_i686.whl", hash = "sha256:83dd2c3f7b70fae9c97bab99fd7a709dc852f0bc3e7482f8cfb378e0c5f1aed8"}, + {file = "rcssmin-1.1.2-cp311-cp311-manylinux1_x86_64.whl", hash = "sha256:2219d704f27006ecd17ef4b5744cac5f68a276be0889b114130660fb798f3583"}, + {file = "rcssmin-1.1.2-cp311-cp311-manylinux2014_aarch64.whl", hash = "sha256:a5e758c8db03a57fef847542bf14d96da75913cc0e2495540c018943c1f2d142"}, + {file = "rcssmin-1.1.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:a0e353ecbfde3dba0a6579a674fc1dcdc1ff7e47ceff3b29beb6e235b53a981c"}, + {file = "rcssmin-1.1.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:140d1c0ba21fb8c3a2bafae164540a6816e8ec3492bea6ace0c52eebd2cf303f"}, + {file = "rcssmin-1.1.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:ef0d472d8f6b8271fef3e388f98085a257703a635556a3ea77287616ab594ea9"}, + {file = "rcssmin-1.1.2-cp312-cp312-manylinux1_i686.whl", hash = "sha256:e58a54e63f79c996284240ec2dfb2992e8b90ad8941b1c70997e256b65940de7"}, + {file = "rcssmin-1.1.2-cp312-cp312-manylinux1_x86_64.whl", hash = "sha256:657324bfb76fa9e97badabe26af97a1622446f33c9073dd0510c7c7e8c7b96da"}, + {file = "rcssmin-1.1.2-cp312-cp312-manylinux2014_aarch64.whl", hash = "sha256:fdffd58868a752cac0400249ce21bddf55e00d3206f8885d4a3aca1dab487070"}, + {file = "rcssmin-1.1.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:82aad2c3526055956fba537ab067ad937b3f57a1bd13c89bf691fced9c24c89d"}, + {file = "rcssmin-1.1.2-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:3a860a1f4304e9813900f70fe6b1d429aff73a6fa30ef07f345f68d0a4e33abc"}, + {file = "rcssmin-1.1.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:0451a2c7e7c1ff893ecb7820de862f2ea6336cc69d473ecb0206212e49c817fc"}, + {file = "rcssmin-1.1.2-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:283b5931eb25e159c0c37bba0717cf3ada2ff77a2827337790cd3921d33ae1eb"}, + {file = "rcssmin-1.1.2-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:4cf7de426fbcce30df31261c1ce84d06fb2ae2f239b0c16ab7e9e083e0462432"}, + {file = "rcssmin-1.1.2-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:47d4d5d67f9ab8f18a6412f8eff843612ebddfff131260fd25a0b273a3d3b1a0"}, + {file = "rcssmin-1.1.2-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:ce4fce4b3f0cf3621f13f6b8aebbe6c90de3587e383d13dbc7c4c1576f27fda8"}, + {file = "rcssmin-1.1.2-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:3ab50d50ecbfa41d8984b545871df447c90a0c55e16a594e0c97057eb694a7af"}, + {file = "rcssmin-1.1.2-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:8eddfed4ac175a97eb228a289f820ff1bffcc3db7c63345e4590a49de7051244"}, + {file = "rcssmin-1.1.2-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:bc2d0ccf449f3f4c385789c9e7898f77fa40f88211cc7d385502f5ea11bc36f4"}, + {file = "rcssmin-1.1.2-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:754c3cab791da42cabfd430289dd991183d2e97f6c36a758ac4fd83c6998cb77"}, + {file = "rcssmin-1.1.2-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:997d3f6defd707f8a7bd39cedb765cedbf9c790ed0bc1f1c8fb65f4026007021"}, + {file = "rcssmin-1.1.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:9c9688d42654f06535a2a052a0c2f02989b9052149f6cd3263ed320a10379657"}, + {file = "rcssmin-1.1.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:a8856db4529e524a632478d88f34d075ec7e772804257d9b99071b8bdd5f3733"}, + {file = "rcssmin-1.1.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:d59a28d6819ad43ed660dfcdf297593f04e8bc227d7abd9548f12a16d6e645f1"}, + {file = "rcssmin-1.1.2-cp38-cp38-manylinux1_i686.whl", hash = "sha256:d1c9efc26682ff610194a0c56b0f192355136e066ff78683806778f0bc5e5093"}, + {file = "rcssmin-1.1.2-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:e5f08c79991c8ee0aa7064aa58ae92b0811d4a84948636ec0219b39d257470aa"}, + {file = "rcssmin-1.1.2-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:2d39b277a568f6208a4beea237c2d1188bd680deaff39f3742278462645a87ed"}, + {file = "rcssmin-1.1.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:2b6a19926f7257ebb7d23040bb0ace05fa43dff7b60d8a9c35bfdf551fa57686"}, + {file = "rcssmin-1.1.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:69283a445483ac439af10ca9f50463c3770ef79a99833af7d5105c75f8ab3c5d"}, + {file = "rcssmin-1.1.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:a8e4c1bfa110d450970df60d904feab71c287e777a3cf522fd20e766483c8ce4"}, + {file = "rcssmin-1.1.2-cp39-cp39-manylinux1_i686.whl", hash = "sha256:19e48f7f66a3fa329215a02b3a952737b0b12f9976cd79ff2c236f96960d71d1"}, + {file = "rcssmin-1.1.2-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:e3ad642a1bfcbbddc3c36ad4c5676ef53267dd7c193c746a2f6670fe5bd03a60"}, + {file = "rcssmin-1.1.2-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:20f8592341960b031967f7ada165e6c8077dfc01eb4092fb970a5a4e64506695"}, + {file = "rcssmin-1.1.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:1c1d9a24132f4c48d080a59c20fce99a4fd9c393eb63f9779f2497ae28992de1"}, + {file = "rcssmin-1.1.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:50576521c1e08e8f137225b8a6e8ae88e867f53dfd82c537616591c67f112aad"}, + {file = "rcssmin-1.1.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:f363c9d242e1afce4fafbbf6bed52452464b19199e66075bed606764f31ca329"}, + {file = "rcssmin-1.1.2.tar.gz", hash = "sha256:bc75eb75bd6d345c0c51fd80fc487ddd6f9fd409dd7861b3fe98dee85018e1e9"}, +] + [[package]] name = "regex" version = "2023.12.25" @@ -1069,6 +1186,62 @@ requests = ">=2.0.0" [package.extras] rsa = ["oauthlib[signedtoken] (>=3.0.0)"] +[[package]] +name = "rjsmin" +version = "1.2.2" +description = "Javascript Minifier" +optional = false +python-versions = "*" +files = [ + {file = "rjsmin-1.2.2-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:4420107304ba7a00b5b9b56cdcd166b9876b34e626829fc4552c85d8fdc3737a"}, + {file = "rjsmin-1.2.2-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:155a2f3312c1f8c6cec7b5080581cafc761dc0e41d64bfb5d46a772c5230ded8"}, + {file = "rjsmin-1.2.2-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:88fcb58d65f88cbfa752d51c1ebe5845553f9706def6d9671e98283411575e3e"}, + {file = "rjsmin-1.2.2-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:6eae13608b88f4ce32e0557c8fdef58e69bb4d293182202a03e800f0d33b5268"}, + {file = "rjsmin-1.2.2-cp310-cp310-manylinux1_i686.whl", hash = "sha256:81f92fb855fb613ebd04a6d6d46483e71fe3c4f22042dc30dcc938fbd748e59c"}, + {file = "rjsmin-1.2.2-cp310-cp310-manylinux1_x86_64.whl", hash = "sha256:897db9bf25538047e9388951d532dc291a629b5d041180a8a1a8c102e9d44b90"}, + {file = "rjsmin-1.2.2-cp310-cp310-manylinux2014_aarch64.whl", hash = "sha256:5938af8c46734f92f74fdc4d0b6324137c0e09f0a8c3825c83e4cfca1b532e40"}, + {file = "rjsmin-1.2.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:0424a7b9096fa2b0ab577c4dc7acd683e6cfb5c718ad39a9fb293cb6cbaba95b"}, + {file = "rjsmin-1.2.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:1714ed93c2bd40c5f970905d2eeda4a6844e09087ae11277d4d43b3e68c32a47"}, + {file = "rjsmin-1.2.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:35596fa6d2d44a5471715c464657123995da78aa6f79bccfbb4b8d6ff7d0a4b4"}, + {file = "rjsmin-1.2.2-cp311-cp311-manylinux1_i686.whl", hash = "sha256:3968667158948355b9a62e9641497aac7ac069c076a595e93199d0fe3a40217a"}, + {file = "rjsmin-1.2.2-cp311-cp311-manylinux1_x86_64.whl", hash = "sha256:d07d14354694f6a47f572f2aa2a1ad74b76723e62a0d2b6df796138b71888247"}, + {file = "rjsmin-1.2.2-cp311-cp311-manylinux2014_aarch64.whl", hash = "sha256:a78dfa6009235b902454ac53264252b7b94f1e43e3a9e97c4cadae88e409b882"}, + {file = "rjsmin-1.2.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:9b7a45001e58243a455d11d2de925cadb8c2a0dc737001de646a0f4d90cf0034"}, + {file = "rjsmin-1.2.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:86c5e657b74b6c9482bb96f18a79d61750f4e8204759cce179f7eb17d395c683"}, + {file = "rjsmin-1.2.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:8c2c30b86c7232443a4a726e1bbee34f800556e581e95fc07194ecbf8e02d1d2"}, + {file = "rjsmin-1.2.2-cp312-cp312-manylinux1_i686.whl", hash = "sha256:8982c3ef27fac26dd6b7d0c55ae98fa550fee72da2db010b87211e4b5dd78a67"}, + {file = "rjsmin-1.2.2-cp312-cp312-manylinux1_x86_64.whl", hash = "sha256:3fc27ae4ece99e2c994cd79df2f0d3f7ac650249f632d19aa8ce85118e33bf0f"}, + {file = "rjsmin-1.2.2-cp312-cp312-manylinux2014_aarch64.whl", hash = "sha256:41113d8d6cae7f7406b30143cc49cc045bbb3fadc2f28df398cea30e1daa60b1"}, + {file = "rjsmin-1.2.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:3aa09a89b2b7aa2b9251329fe0c3e36c2dc2f10f78b8811e5be92a072596348b"}, + {file = "rjsmin-1.2.2-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:5abb8d1241f4ea97950b872fa97a422ba8413fe02358f64128ff0cf745017f07"}, + {file = "rjsmin-1.2.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:5abc686a9ef7eaf208f9ad1fb5fb949556ecb7cc1fee27290eb7f194e01d97bd"}, + {file = "rjsmin-1.2.2-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:076adcf04c34f712c9427fd9ba6a75bbf7aab975650dfc78cbdd0fbdbe49ca63"}, + {file = "rjsmin-1.2.2-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:8cb8947ddd250fce58261b0357846cd5d55419419c0f7dfb131dc4b733579a26"}, + {file = "rjsmin-1.2.2-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:9069c48b6508b9c5b05435e2c6042c2a0e2f97b35d7b9c27ceaea5fd377ffdc5"}, + {file = "rjsmin-1.2.2-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:02b61cf9b6bc518fdac667f3ca3dab051cb8bd1bf4cba28b6d29153ec27990ad"}, + {file = "rjsmin-1.2.2-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:09eca8581797244587916e5e07e36c4c86d54a4b7e5c7697484a95b75803515d"}, + {file = "rjsmin-1.2.2-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:c52b9dd45c837f1c5c2e8d40776f9e63257f8dbd5f79b85f648cc70da6c1e4e9"}, + {file = "rjsmin-1.2.2-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:4fe4ce990412c053a6bcd47d55133927e22fd3d100233d73355f60f9053054c5"}, + {file = "rjsmin-1.2.2-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:aa883b9363b5134239066060879d5eb422a0d4ccf24ccf871f65a5b34c64926f"}, + {file = "rjsmin-1.2.2-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:6f4e95c5ac95b4cbb519917b3aa1d3d92fc6939c371637674c4a42b67b2b3f44"}, + {file = "rjsmin-1.2.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:ae3cd64e18e62aa330b24dd6f7b9809ce0a694afd1f01fe99c21f9acd1cb0ea6"}, + {file = "rjsmin-1.2.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:7999d797fcf805844d2d91598651785497249f592f31674da0964e794b3be019"}, + {file = "rjsmin-1.2.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:e733fea039a7b5ad7c06cc8bf215ee7afac81d462e273b3ab55c1ccc906cf127"}, + {file = "rjsmin-1.2.2-cp38-cp38-manylinux1_i686.whl", hash = "sha256:ccca74461bd53a99ff3304fcf299ea861df89846be3207329cb82d717ce47ea6"}, + {file = "rjsmin-1.2.2-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:88f59ad24f91bf9c25d5c2ca3c84a72eed0028f57a98e3b85a915ece5c25be1e"}, + {file = "rjsmin-1.2.2-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:7a8b56fbd64adcc4402637f0e07b90b441e9981d720a10eb6265118018b42682"}, + {file = "rjsmin-1.2.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:2c24686cfdf86e55692183f7867e72c9e982add479c244eda7b8390f96db2c6c"}, + {file = "rjsmin-1.2.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:6c0d9f9ea8d9cd48cbcdc74a1c2e85d4d588af12bb8f0b672070ae7c9b6e6306"}, + {file = "rjsmin-1.2.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:27abd32c9f5b6e0c0a3bcad43e8e24108c6d6c13a4e6c50c97497ea2b4614bb4"}, + {file = "rjsmin-1.2.2-cp39-cp39-manylinux1_i686.whl", hash = "sha256:e0e009f6f8460901f5144b34ac2948f94af2f9b8c9b5425da705dbc8152c36c2"}, + {file = "rjsmin-1.2.2-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:41e6013cb37a5b3563c19aa35f8e659fa536aa4197a0e3b6a57a381638294a15"}, + {file = "rjsmin-1.2.2-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:62cbd38c9f5090f0a6378a45c415b4f96ae871216cedab0dfa21965620c0be4c"}, + {file = "rjsmin-1.2.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:2fd5254d36f10a17564b63e8bf9ac579c7b5f211364e11e9753ff5b562843c67"}, + {file = "rjsmin-1.2.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:6cf0309d001a0d45d731dbaab1afd0c23d135c9e029fe56c935c1798094686fc"}, + {file = "rjsmin-1.2.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:bfbe333dab8d23f0a71da90e2d8e8b762a739cbd55a6f948b2dfda089b6d5853"}, + {file = "rjsmin-1.2.2.tar.gz", hash = "sha256:8c1bcd821143fecf23242012b55e13610840a839cd467b358f16359010d62dae"}, +] + [[package]] name = "sendgrid" version = "6.11.0" @@ -1341,4 +1514,4 @@ files = [ [metadata] lock-version = "2.0" python-versions = "^3.11" -content-hash = "12cbec16e7f48265242598a4fe781fdcf23a6cf406414ed2576a2c5d58d7fcbb" +content-hash = "72557e12d810af891e12204b03fc2a32184a0ad754dde4409a07bfb9ebe2bab9" diff --git a/pyproject.toml b/pyproject.toml index 1b3e188..135fc27 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -26,6 +26,8 @@ sentry-sdk = { extras = ["django"], version = "^1.40.4" } django-import-export = "^3.3.7" pytest = "^8.2.2" pytest-django = "^4.8.0" +django-compressor = "^4.5.1" +django-libsass = "^0.9" [build-system] requires = ["poetry-core"]