diff --git a/.dockerignore b/.dockerignore index c5f38ed..c04ec2f 100644 --- a/.dockerignore +++ b/.dockerignore @@ -10,6 +10,7 @@ !/manage.py !/package.json !/package-lock.json +!/postcss.config.js !/requirements.dev.txt !/requirements.txt !/rollup.config.mjs diff --git a/.github/workflows/main.yaml b/.github/workflows/main.yaml index 4e6e520..883c4dd 100644 --- a/.github/workflows/main.yaml +++ b/.github/workflows/main.yaml @@ -53,7 +53,6 @@ jobs: - name: Run build run: | npm run build - python manage.py compilescss - python manage.py collectstatic --ignore=*.scss + python manage.py collectstatic - name: Run tests run: python manage.py test bookmarks.e2e --pattern="e2e_test_*.py" diff --git a/.gitignore b/.gitignore index a9663a7..5850eb5 100644 --- a/.gitignore +++ b/.gitignore @@ -183,7 +183,7 @@ typings/ ### Custom # Rollup compilation output /bookmarks/static/bundle.js* -# SASS compilation output +# CSS compilation output /bookmarks/static/theme-*.css* # Collected static files for deployment /static diff --git a/assets/logo-inset.afdesign b/assets/logo-inset.afdesign new file mode 100644 index 0000000..10f0015 Binary files /dev/null and b/assets/logo-inset.afdesign differ diff --git a/bookmarks/static/linkding-screenshot.png b/bookmarks/static/linkding-screenshot.png index 69931c0..99cd028 100644 Binary files a/bookmarks/static/linkding-screenshot.png and b/bookmarks/static/linkding-screenshot.png differ diff --git a/bookmarks/static/logo.png b/bookmarks/static/logo.png index 67552a0..dc63476 100644 Binary files a/bookmarks/static/logo.png and b/bookmarks/static/logo.png differ diff --git a/bookmarks/styles/base.scss b/bookmarks/styles/base.scss deleted file mode 100644 index 9caf728..0000000 --- a/bookmarks/styles/base.scss +++ /dev/null @@ -1,136 +0,0 @@ -/* Main layout */ -body { - margin: 20px 10px; - - @media (min-width: $size-sm) { - // Horizontal padding accounts for checkboxes that show up in bulk edit mode - margin: 20px 32px; - } -} - -header { - margin-bottom: $unit-9; - - .logo { - width: 28px; - height: 28px; - } - - a:hover { - text-decoration: none; - } - - h1 { - margin: 0 0 0 $unit-3; - font-size: $font-size-lg; - } -} - -header .toasts { - margin-bottom: 20px; - - .toast { - margin-bottom: 0.4rem; - } - - .toast a.btn-clear:visited { - color: currentColor; - } -} - -/* Shared components */ - -// Content area component -section.content-area { - h2 { - font-size: $font-size-lg; - } - - .content-area-header { - border-bottom: solid 1px $border-color; - display: flex; - flex-wrap: wrap; - column-gap: $unit-5; - padding-bottom: $unit-1; - margin-bottom: $unit-3; - - h2 { - flex: 0 0 auto; - line-height: $unit-9; - margin: 0; - } - - .header-controls { - flex: 1 1 0; - display: flex; - } - } -} - -// Confirm button component -span.confirmation { - display: flex; - align-items: baseline; - gap: $unit-1; - color: $error-color !important; - - svg { - align-self: center; - } - - .btn.btn-link { - color: $error-color !important; - - &:hover { - text-decoration: underline; - } - } -} - -/* Additional utilities */ - -.truncate { - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; -} - -.text-gray-dark { - color: $gray-color-dark; -} - -.align-baseline { - align-items: baseline; -} - -.align-center { - align-items: center; -} - -.justify-between { - justify-content: space-between; -} - -.mb-4 { - margin-bottom: $unit-4; -} - -.mx-auto { - margin-left: auto; - margin-right: auto; -} - -.btn.btn-wide { - padding-left: $unit-6; - padding-right: $unit-6; -} - -.btn.btn-sm.btn-icon { - display: inline-flex; - align-items: baseline; - gap: $unit-h; - - svg { - align-self: center; - } -} \ No newline at end of file diff --git a/bookmarks/styles/bookmark-details.css b/bookmarks/styles/bookmark-details.css new file mode 100644 index 0000000..ed2f703 --- /dev/null +++ b/bookmarks/styles/bookmark-details.css @@ -0,0 +1,150 @@ +/* Common styles */ +.bookmark-details { + & h2 { + flex: 1 1 0; + align-items: flex-start; + font-size: 1rem; + margin: 0; + } + + & .weblinks { + display: flex; + flex-direction: column; + gap: var(--unit-2); + } + + & a.weblink { + display: flex; + align-items: center; + gap: var(--unit-2); + } + + & a.weblink img, & a.weblink svg { + flex: 0 0 auto; + width: 16px; + height: 16px; + color: var(--text-color); + } + + & a.weblink span { + flex: 1 1 0; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + } + + & .preview-image { + margin: var(--unit-4 0); + + img { + max-width: 100%; + max-height: 200px; + } + } + + & dl { + margin-bottom: 0; + } + + & .assets { + margin-top: var(--unit-2); + + & .asset { + display: flex; + align-items: center; + gap: var(--unit-2); + padding: var(--unit-2) 0; + border-top: var(--unit-o) solid var(--secondary-border-color); + } + + & .asset:last-child { + border-bottom: var(--unit-o) solid var(--secondary-border-color); + } + + & .asset-icon { + display: flex; + align-items: center; + justify-content: center; + } + + & .asset-text { + flex: 1 1 0; + gap: var(--unit-2); + min-width: 0; + display: flex; + } + + & .asset-text .truncate { + flex-shrink: 1; + } + + & .asset-text .filesize { + color: var(--tertiary-text-color); + } + + & .asset-actions { + display: flex; + gap: var(--unit-4); + align-items: center; + + & .btn.btn-link { + height: unset; + padding: 0; + border: none; + } + } + } + + & .assets-actions { + display: flex; + gap: var(--unit-4); + align-items: center; + margin-top: var(--unit-2); + + & .btn.btn-link { + height: unset; + padding: 0; + border: none; + } + } + + & .tags a { + color: var(--alternative-color); + } + + & .status form { + display: flex; + gap: var(--unit-2); + } + + & .status .form-group, .status .form-switch { + margin: 0; + } + + & .actions { + display: flex; + justify-content: space-between; + align-items: center; + } +} + +/* Bookmark details view specific */ +.bookmark-details.page { + display: flex; + flex-direction: column; + gap: var(--unit-6); +} + +/* Bookmark details modal specific */ +.bookmark-details.modal { + & .modal-header { + display: flex; + align-items: flex-start; + gap: var(--unit-2); + } + + & .modal-body { + padding-top: 0; + padding-bottom: 0; + } +} diff --git a/bookmarks/styles/bookmark-details.scss b/bookmarks/styles/bookmark-details.scss deleted file mode 100644 index 25aee2a..0000000 --- a/bookmarks/styles/bookmark-details.scss +++ /dev/null @@ -1,141 +0,0 @@ -/* Common styles */ -.bookmark-details { - h2 { - flex: 1 1 0; - align-items: flex-start; - font-size: 1rem; - margin: 0; - } - - .weblinks { - display: flex; - flex-direction: column; - gap: $unit-2; - } - - a.weblink { - display: flex; - align-items: center; - gap: $unit-2; - } - - a.weblink img, a.weblink svg { - flex: 0 0 auto; - width: 16px; - height: 16px; - color: $body-font-color; - } - - a.weblink span { - flex: 1 1 0; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - } - - .preview-image { - margin: $unit-4 0; - - img { - max-width: 100%; - max-height: 200px; - } - } - - dl { - margin-bottom: 0; - } - - .assets { - margin-top: $unit-2; - } - - .assets .asset { - display: flex; - align-items: center; - gap: $unit-3; - padding: $unit-2 0; - border-top: $unit-o solid $border-color-light; - } - - .assets .asset:last-child { - border-bottom: $unit-o solid $border-color-light; - } - - .assets .asset-icon { - display: flex; - align-items: center; - justify-content: center; - } - - .assets .asset-text { - flex: 1 1 0; - gap: $unit-2; - min-width: 0; - display: flex; - } - - .assets .asset-text .truncate { - flex-shrink: 1; - } - - .assets .asset-text .filesize { - color: $gray-color; - } - - .assets .asset-actions, .assets-actions { - display: flex; - gap: $unit-4; - align-items: center; - } - - .assets .asset-actions .btn, .assets-actions .btn { - height: unset; - padding: 0; - border: none; - } - - .assets-actions { - margin-top: $unit-2; - } - - .tags a { - color: $alternative-color; - } - - .status form { - display: flex; - gap: $unit-2; - } - - .status .form-group, .status .form-switch { - margin: 0; - } - - .actions { - display: flex; - justify-content: space-between; - align-items: center; - } -} - -/* Bookmark details view specific */ -.bookmark-details.page { - display: flex; - flex-direction: column; - gap: $unit-6; -} - -/* Bookmark details modal specific */ -.bookmark-details.modal { - .modal-header { - display: flex; - align-items: flex-start; - gap: $unit-2; - } - - .modal-body { - padding-top: 0; - padding-bottom: 0; - } -} diff --git a/bookmarks/styles/bookmark-form.css b/bookmarks/styles/bookmark-form.css new file mode 100644 index 0000000..25c8eaf --- /dev/null +++ b/bookmarks/styles/bookmark-form.css @@ -0,0 +1,48 @@ +.bookmarks-form-page { + section { + max-width: 550px; + margin: 0 auto; + } +} + +.bookmarks-form { + & .btn.btn-link.form-icon { + padding: 0; + width: 20px; + height: 20px; + visibility: hidden; + --btn-icon-color: var(--tertiary-text-color); + + & > svg { + width: 20px; + height: 20px; + } + } + + & .has-icon-right > input, & .has-icon-right > textarea { + padding-right: 30px; + } + + & .has-icon-right > input:placeholder-shown ~ .btn.form-icon, + & .has-icon-right > textarea:placeholder-shown ~ .btn.form-icon { + visibility: visible; + } + + & .form-icon.loading { + visibility: hidden; + } + + & .form-input-hint.bookmark-exists { + display: none; + color: var(--warning-color); + } + + & .form-input-hint.auto-tags { + display: none; + color: var(--success-color); + } + + & details.notes textarea { + box-sizing: border-box; + } +} \ No newline at end of file diff --git a/bookmarks/styles/bookmark-form.scss b/bookmarks/styles/bookmark-form.scss deleted file mode 100644 index 1b31754..0000000 --- a/bookmarks/styles/bookmark-form.scss +++ /dev/null @@ -1,49 +0,0 @@ -.bookmarks-form { - - .btn.form-icon { - padding: 0; - width: 20px; - height: 20px; - visibility: hidden; - color: $gray-color; - - &:focus, - &:hover, - &:active, - &.active { - color: $gray-color-dark; - } - - > svg { - width: 20px; - height: 20px; - } - } - - .has-icon-right > input, .has-icon-right > textarea { - padding-right: 30px; - } - - .has-icon-right > input:placeholder-shown ~ .btn.form-icon, - .has-icon-right > textarea:placeholder-shown ~ .btn.form-icon { - visibility: visible; - } - - .form-icon.loading { - visibility: hidden; - } - - .form-input-hint.bookmark-exists { - display: none; - color: $warning-color; - } - - .form-input-hint.auto-tags { - display: none; - color: $success-color; - } - - details.notes textarea { - box-sizing: border-box; - } -} \ No newline at end of file diff --git a/bookmarks/styles/bookmark-page.css b/bookmarks/styles/bookmark-page.css new file mode 100644 index 0000000..42a823a --- /dev/null +++ b/bookmarks/styles/bookmark-page.css @@ -0,0 +1,457 @@ +:root { + --bookmark-title-color: var(--primary-text-color); + --bookmark-title-weight: 500; + --bookmark-description-color: var(--text-color); + --bookmark-description-weight: 400; + --bookmark-actions-color: var(--secondary-text-color); + --bookmark-actions-hover-color: var(--text-color); + --bookmark-actions-weight: 400; + --bulk-actions-bg-color: var(--gray-50); +} + +/* Bookmark page grid */ +.bookmarks-page.grid { + grid-gap: var(--unit-9); +} + +/* Bookmark area header controls */ +.bookmarks-page .search-container { + flex: 1 1 0; + display: flex; + max-width: 300px; + margin-left: auto; + + & form { + width: 100%; + } + + @media (max-width: 600px) { + max-width: initial; + margin-left: 0; + } + + /* Regular input */ + + & input[type='search'] { + height: var(--control-size); + -webkit-appearance: none; + } + + /* Enhanced auto-complete input */ + /* This needs a bit more wrangling to make the CSS component align with the attached button */ + + & .form-autocomplete { + height: var(--control-size); + + & .form-autocomplete-input { + width: 100%; + height: var(--control-size); + + & input[type='search'] { + width: 100%; + height: 100%; + margin: 0; + border: none; + } + } + } + + /* Group search options button with search button */ + height: var(--control-size); + border-radius: var(--border-radius); + box-shadow: var(--box-shadow-xs); + + & input, & .form-autocomplete-input { + border-top-right-radius: 0; + border-bottom-right-radius: 0; + box-shadow: none; + } + + & .dropdown-toggle { + border-left: none; + border-top-left-radius: 0; + border-bottom-left-radius: 0; + box-shadow: none; + outline-offset: calc(var(--focus-outline-offset) * -1); + } + + /* Search option menu styles */ + + & .dropdown { + & .menu { + padding: var(--unit-4); + min-width: 250px; + font-size: var(--font-size-sm); + } + + & .menu .actions { + margin-top: var(--unit-4); + display: flex; + justify-content: space-between; + } + + & .form-group:first-of-type { + margin-top: 0; + } + + & .form-group { + margin-bottom: var(--unit-3); + } + + & .radio-group { + & .form-label { + margin-bottom: var(--unit-1); + } + + & .form-radio.form-inline { + margin: 0 var(--unit-2) 0 0; + padding: 0; + display: inline-flex; + align-items: center; + column-gap: var(--unit-1); + } + + & .form-icon { + top: 0; + position: relative; + } + } + } +} + +/* Bookmark list */ +ul.bookmark-list { + list-style: none; + margin: 0; + padding: 0; + + /* Increase line-height for better separation within / between items */ + line-height: 1.1rem; +} + +@keyframes appear { + 0% { + opacity: 0; + } + 90% { + opacity: 0; + } + 100% { + opacity: 1; + } +} + +/* Bookmarks */ +li[ld-bookmark-item] { + position: relative; + display: flex; + gap: var(--unit-2); + margin-top: 0; + margin-bottom: var(--unit-3); + + & .content { + flex: 1 1 0; + min-width: 0; + } + + & img.preview-image { + flex: 0 0 auto; + width: 100px; + height: 60px; + margin-top: var(--unit-h); + object-fit: cover; + border-radius: var(--border-radius); + border: solid 1px var(--border-color); + } + + & .form-checkbox.bulk-edit-checkbox { + display: none; + } + + & .title { + position: relative; + } + + & .title img { + position: absolute; + width: 16px; + height: 16px; + left: 0; + top: 50%; + transform: translateY(-50%); + pointer-events: none; + } + + & .title img + a { + padding-left: 22px; + } + + & .title a { + color: var(--bookmark-title-color); + font-weight: var(--bookmark-title-weight); + display: block; + width: 100%; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + } + + & .title a[data-tooltip]:hover::after, & .title a[data-tooltip]:focus::after { + content: attr(data-tooltip); + position: absolute; + z-index: 10; + top: 100%; + left: 50%; + transform: translateX(-50%); + width: max-content; + max-width: 90%; + height: fit-content; + background-color: #292f62; + color: #fff; + padding: var(--unit-1); + border-radius: var(--border-radius); + border: 1px solid #424a8c; + font-size: var(--font-size-sm); + font-style: normal; + white-space: normal; + pointer-events: none; + animation: 0.3s ease 0s appear; + } + + @media (pointer: coarse) { + & .title a[data-tooltip]::after { + display: none; + } + } + + &.unread .title a { + font-style: italic; + } + + & .url-path, & .url-display { + font-size: var(--font-size-sm); + color: var(--secondary-link-color); + } + + & .description { + color: var(--bookmark-description-color); + font-weight: var(--bookmark-description-weight); + } + + & .description.separate { + display: -webkit-box; + -webkit-box-orient: vertical; + -webkit-line-clamp: var(--ld-bookmark-description-max-lines, 1); + overflow: hidden; + } + + & .tags { + & a, & a:visited:hover { + color: var(--alternative-color); + } + } + + & .actions, & .extra-actions { + display: flex; + align-items: baseline; + flex-wrap: wrap; + column-gap: var(--unit-2); + } + + @media (max-width: 600px) { + & .extra-actions { + width: 100%; + margin-top: var(--unit-1); + } + } + + & .actions { + color: var(--bookmark-actions-color); + font-size: var(--font-size-sm); + + & a, & button.btn-link { + color: var(--bookmark-actions-color); + --btn-icon-color: var(--bookmark-actions-color); + font-weight: var(--bookmark-actions-weight); + padding: 0; + height: auto; + vertical-align: unset; + border: none; + box-sizing: border-box; + transition: none; + text-decoration: none; + + &:focus, + &:hover, + &:active, + &.active { + color: var(--bookmark-actions-hover-color); + --btn-icon-color: var(--bookmark-actions-hover-color); + } + } + } +} + +.bookmark-pagination { + margin-top: var(--unit-4); + + /* Remove left padding from first pagination link */ + + & .page-item:first-child a { + padding-left: 0; + } +} + +.tag-cloud { + /* Increase line-height for better separation within / between items */ + line-height: 1.1rem; + + & .selected-tags { + margin-bottom: var(--unit-4); + + & a, + & a:visited:hover { + color: var(--error-color); + } + } + + & .unselected-tags { + & a, + & a:visited:hover { + color: var(--alternative-color); + } + } + + & .group { + margin-bottom: var(--unit-3); + } + + & .highlight-char { + font-weight: bold; + text-transform: uppercase; + color: var(--alternative-color-dark); + } +} + +/* Bookmark notes */ +ul.bookmark-list { + & .notes { + display: none; + max-height: 300px; + margin: var(--unit-1) 0; + overflow-y: auto; + background: var(--body-color-contrast); + border-radius: var(--border-radius); + } + + & .notes .markdown { + padding: var(--unit-2) var(--unit-3); + } + + &.show-notes .notes, + & li.show-notes .notes { + display: block; + } +} + +/* Bookmark bulk edit */ +:root { + --bulk-edit-toggle-width: 16px; + --bulk-edit-toggle-offset: 8px; + --bulk-edit-bar-offset: calc(var(--bulk-edit-toggle-width) + (2 * var(--bulk-edit-toggle-offset))); + --bulk-edit-transition-duration: 400ms; +} + +[ld-bulk-edit] { + & .bulk-edit-bar { + margin-top: -1px; + margin-left: calc(-1 * var(--bulk-edit-bar-offset)); + margin-bottom: var(--unit-4); + max-height: 0; + overflow: hidden; + transition: max-height var(--bulk-edit-transition-duration); + background: var(--bulk-actions-bg-color); + } + + &.active .bulk-edit-bar { + max-height: 37px; + border-bottom: solid 1px var(--secondary-border-color); + } + + /* Hide section border when bulk edit bar is opened, otherwise borders overlap in dark mode due to using contrast colors */ + &.active section:first-of-type .content-area-header { + border-bottom-color: transparent; + } + + /* remove overflow after opening animation, otherwise tag autocomplete overlay gets cut off */ + + &.active:not(.activating) .bulk-edit-bar { + overflow: visible; + } + + /* All checkbox */ + + & .form-checkbox.bulk-edit-checkbox.all { + display: block; + width: var(--bulk-edit-toggle-width); + margin: 0 0 0 var(--bulk-edit-toggle-offset); + padding: 0; + } + + /* Bookmark checkboxes */ + + & li[ld-bookmark-item] .form-checkbox.bulk-edit-checkbox { + display: block; + position: absolute; + width: var(--bulk-edit-toggle-width); + min-height: var(--bulk-edit-toggle-width); + left: calc(-1 * var(--bulk-edit-toggle-width) - var(--bulk-edit-toggle-offset)); + top: 50%; + transform: translateY(-50%); + padding: 0; + margin: 0; + visibility: hidden; + opacity: 0; + transition: all var(--bulk-edit-transition-duration); + + .form-icon { + top: 0; + } + } + + &.active li[ld-bookmark-item] .form-checkbox.bulk-edit-checkbox { + visibility: visible; + opacity: 1; + } + + /* Actions */ + + & .bulk-edit-actions { + display: flex; + align-items: center; + padding: var(--unit-1) 0; + border-top: solid 1px var(--secondary-border-color); + gap: var(--unit-2); + + & button { + --control-padding-x-sm: 0; + } + + & button:hover { + text-decoration: underline; + } + + & > input, + & .form-autocomplete, + & select { + width: auto; + max-width: 140px; + -webkit-appearance: none; + } + + & .select-across { + margin: 0 0 0 auto; + font-size: var(--font-size-sm); + } + } +} diff --git a/bookmarks/styles/bookmark-page.scss b/bookmarks/styles/bookmark-page.scss deleted file mode 100644 index a4d63fe..0000000 --- a/bookmarks/styles/bookmark-page.scss +++ /dev/null @@ -1,408 +0,0 @@ -.bookmarks-page.grid { - grid-gap: $unit-9; -} - -/* Bookmark area header controls */ -.bookmarks-page .content-area-header { - --searchbox-max-width: 350px; - - @media (max-width: $size-sm) { - --searchbox-max-width: initial; - flex-direction: column; - } -} - -.bookmarks-page .search-container { - flex: 1 1 0; - display: flex; - justify-content: flex-end; - - // Regular input - input[type='search'] { - height: $control-size; - -webkit-appearance: none; - } - - // Enhanced auto-complete input - // This needs a bit more wrangling to make the CSS component align with the attached button - .form-autocomplete { - height: $control-size; - - .form-autocomplete-input { - width: 100%; - height: $control-size; - - input[type='search'] { - width: 100%; - height: 100%; - margin: 0; - border: none; - } - } - } - - .input-group { - flex: 1 1 0; - min-width: var(--searchbox-min-width); - max-width: var(--searchbox-max-width); - } - - .input-group > :first-child { - flex: 1 1 0; - } - - // Group search options button with search button - .input-group input[type='submit'] { - border-top-right-radius: 0; - border-bottom-right-radius: 0; - } - - .dropdown-toggle { - border-top-left-radius: 0; - border-bottom-left-radius: 0; - } - - .dropdown { - margin-left: -1px; - } - - // Search option menu styles - .dropdown { - .menu { - padding: $unit-4; - min-width: 250px; - font-size: $font-size-sm; - } - - .menu .actions { - margin-top: $unit-4; - display: flex; - justify-content: space-between; - } - - .radio-group { - margin-bottom: $unit-1; - - .form-label { - padding-bottom: 0; - } - - .form-radio.form-inline { - margin: 0 $unit-2 0 0; - padding: 0; - display: inline-flex; - align-items: center; - column-gap: $unit-1; - } - - .form-icon { - top: 0; - position: relative; - } - } - } -} - -/* Bookmark list */ -ul.bookmark-list { - list-style: none; - margin: 0; - padding: 0; - - /* Increase line-height for better separation within / between items */ - line-height: 1.1rem; -} - -@keyframes appear { - 0% { - opacity: 0; - } - 90% { - opacity: 0; - } - 100% { - opacity: 1; - } -} - -/* Bookmarks */ -li[ld-bookmark-item] { - position: relative; - display: flex; - gap: $unit-2; - margin-top: $unit-2; - - .content { - flex: 1 1 0; - min-width: 0; - } - - img.preview-image { - flex: 0 0 auto; - width: 100px; - height: 60px; - margin-top: $unit-h; - object-fit: cover; - border-radius: $border-radius; - border: solid 1px $border-color-dark; - } - - .form-checkbox.bulk-edit-checkbox { - display: none; - } - - .title { - position: relative; - } - - .title img { - position: absolute; - width: 16px; - height: 16px; - left: 0; - top: 50%; - transform: translateY(-50%); - pointer-events: none; - } - - .title img + a { - padding-left: 22px; - } - - .title a { - display: block; - width: 100%; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - } - - .title a[data-tooltip]:hover::after, .title a[data-tooltip]:focus::after { - content: attr(data-tooltip); - position: absolute; - z-index: 10; - top: 100%; - left: 50%; - transform: translateX(-50%); - width: max-content; - max-width: 90%; - height: fit-content; - background-color: #292f62; - color: #fff; - padding: $unit-1; - border-radius: $border-radius; - border: 1px solid #424a8c; - font-size: $font-size-sm; - font-style: normal; - white-space: normal; - pointer-events: none; - animation: 0.3s ease 0s appear; - } - - @media (pointer:coarse) { - .title a[data-tooltip]::after { - display: none; - } - } - - &.unread .title a { - font-style: italic; - } - - .url-path, .url-display { - font-size: $font-size-sm; - color: $secondary-link-color; - } - - .description { - color: $gray-color-dark; - } - - .description.separate { - display: -webkit-box; - -webkit-box-orient: vertical; - -webkit-line-clamp: var(--ld-bookmark-description-max-lines, 1); - overflow: hidden; - } - - .tags { - a, a:visited:hover { - color: $alternative-color; - } - } - - .actions, .extra-actions { - display: flex; - align-items: baseline; - flex-wrap: wrap; - column-gap: $unit-2; - } - - @media (max-width: $size-sm) { - .extra-actions { - width: 100%; - margin-top: $unit-1; - } - } - - .actions { - font-size: $font-size-sm; - - a, button.btn-link { - color: $gray-color; - padding: 0; - height: auto; - vertical-align: unset; - border: none; - transition: none; - text-decoration: none; - - &:focus, - &:hover, - &:active, - &.active { - color: $gray-color-dark; - } - } - } -} - -.bookmark-pagination { - margin-top: $unit-4; -} - -.tag-cloud { - /* Increase line-height for better separation within / between items */ - line-height: 1.1rem; - - .selected-tags { - margin-bottom: $unit-4; - - a, a:visited:hover { - color: $error-color; - } - } - - .unselected-tags { - a, a:visited:hover { - color: $alternative-color; - } - } - - .group { - margin-bottom: $unit-2; - } - - .highlight-char { - font-weight: bold; - text-transform: uppercase; - color: $alternative-color-dark; - } -} - -/* Bookmark notes */ -ul.bookmark-list { - .notes { - display: none; - max-height: 300px; - margin: $unit-1 0; - overflow-y: auto; - } - - .notes .markdown { - padding: $unit-2 $unit-3; - } - - &.show-notes .notes, - li.show-notes .notes { - display: block; - } -} - -/* Bookmark bulk edit */ -$bulk-edit-toggle-width: 16px; -$bulk-edit-toggle-offset: 8px; -$bulk-edit-bar-offset: $bulk-edit-toggle-width + (2 * $bulk-edit-toggle-offset); -$bulk-edit-transition-duration: 400ms; - -[ld-bulk-edit] { - .bulk-edit-bar { - margin-top: -1px; - margin-left: -$bulk-edit-bar-offset; - margin-bottom: $unit-3; - max-height: 0; - overflow: hidden; - transition: max-height $bulk-edit-transition-duration; - } - - &.active .bulk-edit-bar { - max-height: 37px; - border-bottom: solid 1px $border-color; - } - - /* remove overflow after opening animation, otherwise tag autocomplete overlay gets cut off */ - &.active:not(.activating) .bulk-edit-bar { - overflow: visible; - } - - /* All checkbox */ - .form-checkbox.bulk-edit-checkbox.all { - display: block; - width: $bulk-edit-toggle-width; - margin: 0 0 0 $bulk-edit-toggle-offset; - padding: 0; - } - - /* Bookmark checkboxes */ - li[ld-bookmark-item] .form-checkbox.bulk-edit-checkbox { - display: block; - position: absolute; - width: $bulk-edit-toggle-width; - min-height: $bulk-edit-toggle-width; - left: -$bulk-edit-toggle-width - $bulk-edit-toggle-offset; - top: 50%; - transform: translateY(-50%); - padding: 0; - margin: 0; - visibility: hidden; - opacity: 0; - transition: all $bulk-edit-transition-duration; - - .form-icon { - top: 0; - } - } - - &.active li[ld-bookmark-item] .form-checkbox.bulk-edit-checkbox { - visibility: visible; - opacity: 1; - } - - /* Actions */ - .bulk-edit-actions { - display: flex; - align-items: center; - padding: $unit-1 0; - border-top: solid 1px $border-color; - gap: $unit-2; - - button { - padding: 0 !important; - } - - button:hover { - text-decoration: underline; - } - - > input, .form-autocomplete, select { - width: auto; - max-width: 140px; - -webkit-appearance: none; - } - - .select-across { - margin: 0 0 0 auto; - font-size: $font-size-sm; - } - } -} diff --git a/bookmarks/styles/components.css b/bookmarks/styles/components.css new file mode 100644 index 0000000..f485f0e --- /dev/null +++ b/bookmarks/styles/components.css @@ -0,0 +1,60 @@ +/* Shared components */ + +/* Content area component */ +section.content-area { + h2 { + font-size: var(--font-size-lg); + } + + .content-area-header { + border-bottom: solid 1px var(--secondary-border-color); + display: flex; + flex-wrap: wrap; + column-gap: var(--unit-5); + padding-bottom: var(--unit-2); + margin-bottom: var(--unit-4); + + h2 { + flex: 0 0 auto; + line-height: var(--unit-9); + margin: 0; + } + + .header-controls { + flex: 1 1 0; + display: flex; + } + } +} + +@media (max-width: 600px) { + section.content-area .content-area-header { + flex-direction: column; + } +} + +/* Confirm button component */ +span.confirmation { + display: flex; + align-items: baseline; + gap: var(--unit-1); + color: var(--error-color) !important; + + svg { + align-self: center; + } + + .btn.btn-link { + color: var(--error-color) !important; + + &:hover { + text-decoration: underline; + } + } +} + +/* Divider */ +.divider { + border-bottom: solid 1px var(--secondary-border-color); + margin: var(--unit-5) 0; +} \ No newline at end of file diff --git a/bookmarks/styles/layout.css b/bookmarks/styles/layout.css new file mode 100644 index 0000000..fb759f4 --- /dev/null +++ b/bookmarks/styles/layout.css @@ -0,0 +1,39 @@ +/* Main layout */ +body { + margin: 20px 10px; + + @media (min-width: 600px) { + /* Horizontal offset accounts for checkboxes that show up in bulk edit mode */ + margin: 20px 32px; + } +} + +header { + margin-bottom: var(--unit-9); + + .logo { + width: 28px; + height: 28px; + } + + a:hover { + text-decoration: none; + } + + h1 { + margin: 0 0 0 var(--unit-3); + font-size: var(--font-size-lg); + } +} + +header .toasts { + margin-bottom: 20px; + + .toast { + margin-bottom: 0.4rem; + } + + .toast a.btn-clear:visited { + color: currentColor; + } +} diff --git a/bookmarks/styles/markdown.css b/bookmarks/styles/markdown.css new file mode 100644 index 0000000..f75460c --- /dev/null +++ b/bookmarks/styles/markdown.css @@ -0,0 +1,40 @@ +.markdown { + & p, & ul, & ol, & pre, & blockquote { + margin: 0 0 var(--unit-2) 0; + } + + & > *:first-child { + margin-top: 0; + } + + & > *:last-child { + margin-bottom: 0; + } + + & ul, & ol { + margin-left: var(--unit-4); + } + + & ul li, & ol li { + margin-top: var(--unit-1); + } + + & pre { + padding: var(--unit-1) var(--unit-2); + background-color: var(--code-bg-color); + border-radius: var(--unit-1); + overflow-x: auto; + } + + & pre code { + background: none; + box-shadow: none; + padding: 0; + } + + & > pre:first-child:last-child { + padding: 0; + background: none; + border-radius: 0; + } +} diff --git a/bookmarks/styles/markdown.scss b/bookmarks/styles/markdown.scss deleted file mode 100644 index df88b5d..0000000 --- a/bookmarks/styles/markdown.scss +++ /dev/null @@ -1,40 +0,0 @@ -.markdown { - p, ul, ol, pre, blockquote { - margin: 0 0 $unit-2 0; - } - - > *:first-child { - margin-top: 0; - } - - > *:last-child { - margin-bottom: 0; - } - - ul, ol { - margin-left: $unit-4; - } - - ul li, ol li { - margin-top: $unit-1; - } - - pre { - padding: $unit-1 $unit-2; - background-color: $code-bg-color; - border-radius: $unit-1; - overflow-x: auto; - } - - pre code { - background: none; - box-shadow: none; - padding: 0; - } - - > pre:first-child:last-child { - padding: 0; - background: none; - border-radius: 0; - } -} diff --git a/bookmarks/styles/reader-mode.scss b/bookmarks/styles/reader-mode.css similarity index 100% rename from bookmarks/styles/reader-mode.scss rename to bookmarks/styles/reader-mode.css diff --git a/bookmarks/styles/responsive.scss b/bookmarks/styles/responsive.css similarity index 80% rename from bookmarks/styles/responsive.scss rename to bookmarks/styles/responsive.css index 6c33771..de0dde8 100644 --- a/bookmarks/styles/responsive.scss +++ b/bookmarks/styles/responsive.css @@ -1,10 +1,3 @@ -.container { - margin-left: auto; - margin-right: auto; - width: 100%; - max-width: $size-lg; -} - .show-sm, .show-md { display: none !important; @@ -26,11 +19,18 @@ width: 100%; } +.container { + margin-left: auto; + margin-right: auto; + width: 100%; + max-width: var(--size-lg); +} + .grid { --grid-columns: 3; display: grid; grid-template-columns: repeat(var(--grid-columns), 1fr); - grid-gap: $unit-4; + grid-gap: var(--unit-4); } .grid > * { @@ -46,18 +46,18 @@ } .col-1 { - grid-column: unquote("span min(1, var(--grid-columns))"); + grid-column: span min(1, var(--grid-columns)); } .col-2 { - grid-column: unquote("span min(2, var(--grid-columns))"); + grid-column: span min(2, var(--grid-columns)); } .col-3 { - grid-column: unquote("span min(3, var(--grid-columns))"); + grid-column: span min(3, var(--grid-columns)); } -@media (max-width: $size-md) { +@media (max-width: 840px) { .hide-md { display: none !important; } @@ -86,7 +86,7 @@ } } -@media (max-width: $size-sm) { +@media (max-width: 600px) { .hide-sm { display: none !important; } diff --git a/bookmarks/styles/settings.scss b/bookmarks/styles/settings.css similarity index 61% rename from bookmarks/styles/settings.scss rename to bookmarks/styles/settings.css index 0b7d8b3..d60dfac 100644 --- a/bookmarks/styles/settings.scss +++ b/bookmarks/styles/settings.css @@ -1,9 +1,9 @@ .settings-page { section.content-area { - margin-bottom: $unit-10; + margin-bottom: var(--unit-10); h2 { - margin-bottom: $unit-3; + margin-bottom: var(--unit-3); } } @@ -17,6 +17,10 @@ } section.about table { - max-width: 500px; + max-width: 400px; + } + + & .form-group { + margin-bottom: var(--unit-4); } } diff --git a/bookmarks/styles/spectre.scss b/bookmarks/styles/spectre.scss deleted file mode 100644 index 628b7de..0000000 --- a/bookmarks/styles/spectre.scss +++ /dev/null @@ -1,204 +0,0 @@ -// Customized Spectre CSS imports, removing modules that are not used -// See node_modules/spectre.css/src/spectre.scss for the original version - -// Variables and mixins -@import "../../node_modules/spectre.css/src/variables"; - -// Customize variables to reduce font and control sizes - -// Can use CSS variables for font sizes, as they are not used in SCSS calculations -$font-size: var(--font-size); -$font-size-sm: var(--font-size-sm); -$font-size-lg: var(--font-size-lg); - -// Can't use CSS variables for these, used in SCSS calculations -$line-height: 1rem; -$control-size: $unit-8; -$control-size-sm: $unit-6; -$control-size-lg: $unit-9; - -// Declare defaults for CSS variables, expose SCSS variables as CSS variables -html { - --font-size: 0.7rem; - --font-size-sm: 0.65rem; - --font-size-lg: 0.8rem; - - --control-size: #{$control-size}; - --control-size-sm: #{$control-size-sm}; - --control-size-lg: #{$control-size-lg}; -} - -// Mixins -@import "../../node_modules/spectre.css/src/mixins"; - -/*! Spectre.css v#{$version} | MIT License | github.com/picturepan2/spectre */ -// Reset and dependencies -@import "../../node_modules/spectre.css/src/normalize"; -@import "../../node_modules/spectre.css/src/base"; - -// Elements -@import "../../node_modules/spectre.css/src/typography"; -@import "../../node_modules/spectre.css/src/asian"; -@import "../../node_modules/spectre.css/src/tables"; -@import "../../node_modules/spectre.css/src/buttons"; -@import "../../node_modules/spectre.css/src/forms"; -@import "../../node_modules/spectre.css/src/labels"; -@import "../../node_modules/spectre.css/src/codes"; -@import "../../node_modules/spectre.css/src/media"; - -// Components -@import "../../node_modules/spectre.css/src/badges"; -@import "../../node_modules/spectre.css/src/dropdowns"; -@import "../../node_modules/spectre.css/src/empty"; -@import "../../node_modules/spectre.css/src/menus"; -@import "../../node_modules/spectre.css/src/modals"; -@import "../../node_modules/spectre.css/src/pagination"; -@import "../../node_modules/spectre.css/src/tabs"; -@import "../../node_modules/spectre.css/src/toasts"; -@import "../../node_modules/spectre.css/src/tooltips"; - -// Utility classes -@import "../../node_modules/spectre.css/src/animations"; -@import "../../node_modules/spectre.css/src/utilities"; - -// Auto-complete component -@import "../../node_modules/spectre.css/src/autocomplete"; - - -/* Spectre overrides / fixes */ - -// Fix up visited styles -a:visited { - color: $link-color; -} - -a:visited:hover { - color: $link-color-dark; -} - -.btn-link:visited:not(.btn-primary) { - color: $link-color; -} - -.btn-link:visited:not(.btn-primary):hover { - color: $link-color-dark; -} - -// Disable transitions on buttons, which can otherwise flicker while loading CSS file -// something to do with .btn applying a transition for background, and then .btn-link setting a different background -.btn { - transition: none !important; -} - -// Make code work with light and dark theme -code { - color: $gray-color-dark; - background-color: $code-bg-color; - box-shadow: 1px 1px 0 $code-shadow-color; -} - -// Remove left padding from first pagination link -.pagination .page-item:first-child a { - padding-left: 0; -} - -// Override border color for tab block -.tab-block { - border-bottom: solid 1px $border-color; -} - -// Fix padding for first menu item -ul.menu li:first-child { - margin-top: 0; -} - -// Form auto-complete menu -.form-autocomplete .menu { - .menu-item.selected > a, .menu-item > a:hover { - background: $secondary-color; - color: $primary-color; - } - - .group-item, .group-item:hover { - color: $gray-color; - text-transform: uppercase; - background: none; - font-size: 0.6rem; - font-weight: bold; - } -} - -.modal { - // Add border to separate from background in dark mode - .modal-container { - border: solid 1px $border-color; - } - - // Fix modal header to use default color - .modal-header { - color: inherit; - } -} - -// Customize modal animation -@keyframes fade-in { - 0% { - opacity: 0; - } - 100% { - opacity: 1; - } -} - -@keyframes fade-out { - 0% { - opacity: 1; - } - 100% { - opacity: 0; - } -} - -.modal.active .modal-container, .modal.active .modal-overlay { - animation: fade-in .15s ease 1; -} - -.modal.active.closing .modal-container, .modal.active.closing .modal-overlay { - animation: fade-out .15s ease 1; -} - -// Customize menu animation -.dropdown .menu { - animation: fade-in .15s ease 1; -} - -// Modal close button -.modal .modal-header button.close { - background: none; - border: none; - padding: 0; - line-height: 0; - cursor: pointer; - opacity: .85; - color: $gray-color-dark; - - &:hover { - opacity: 1; - } -} - -// Increase input font size on small viewports to prevent zooming on focus the input -// on mobile devices. 430px relates to the "normalized" iPhone 14 Pro Max -// viewport size -@media screen and (max-width: 430px) { - .form-input { - font-size: 16px; - } -} - -// Hide tooltips on mobile -@media (pointer:coarse) { - .tooltip::after { - display: none; - } -} diff --git a/bookmarks/styles/theme-dark.css b/bookmarks/styles/theme-dark.css new file mode 100644 index 0000000..6f4f800 --- /dev/null +++ b/bookmarks/styles/theme-dark.css @@ -0,0 +1,143 @@ +@import "theme-light.css"; + +:root { + /* Color palette */ + --contrast-5: hsla(241, 65%, 85%, 0.06); + --contrast-10: hsla(241, 60%, 80%, 0.14); + --contrast-20: hsla(241, 64%, 82%, 0.23); + --contrast-30: hsla(241, 69%, 84%, 0.32); + --contrast-40: hsla(241, 73%, 86%, 0.41); + --contrast-50: hsla(241, 78%, 88%, 0.5); + --contrast-60: hsla(241, 82%, 90%, 0.58); + --contrast-70: hsla(241, 87%, 92%, 0.69); + --contrast-80: hsla(241, 91%, 94%, 0.8); + --contrast-90: hsla(241, 96%, 96%, 0.9); + + --primary-color: hsl(241, 75%, 64%); + --primary-color-highlight: hsl(241, 75%, 68%); + --primary-color-shade: hsl(241, 75%, 64%, 0.42); + + --alternative-color: hsl(179, 50%, 58%); + --alternative-color-dark: hsl(179, 80%, 75%); + + --success-color: hsl(142, 76%, 36%); + --success-color-highlight: hsl(142, 76%, 40%); + --success-color-shade: hsla(142, 76%, 36%, 0.1); + + --warning-color: hsl(38, 92%, 50%); + --warning-color-highlight: hsl(38, 92%, 55%); + --warning-color-shade: hsla(38, 92%, 50%, 0.1); + + --error-color: hsl(0, 80%, 60%); + --error-color-highlight: hsl(0, 72%, 60%); + --error-color-shade: hsla(0, 72%, 51%, 0.1); + + /* Core colors */ + --text-color: var(--gray-300); + --secondary-text-color: var(--gray-400); + --tertiary-text-color: var(--gray-500); + --contrast-text-color: #fff; + --primary-text-color: hsl(241, 82%, 82%); + + --link-color: var(--primary-text-color); + --secondary-link-color: hsla(241, 82%, 82%, 0.8); + + --icon-color: var(--text-color); + + --border-color: var(--contrast-30); + --secondary-border-color: var(--contrast-20); + + --body-color: hsl(241, 15%, 14%); + --body-color-contrast: var(--contrast-10); + + /* Focus */ + --focus-outline: 2px solid hsl(241, 100%, 78%); + --focus-outline-offset: 2px; + + /* Shadows */ + --box-shadow-xs: none; + --box-shadow: none; + --box-shadow-lg: none; +} + +:root { + --input-bg-color: var(--contrast-5); + --input-disabled-bg-color: var(--contrast-30); + --input-text-color: var(--text-color); + --input-hint-color: var(--secondary-text-color); + --input-border-color: var(--border-color); + --input-placeholder-color: var(--tertiary-text-color); + --input-box-shadow: var(--box-shadow-xs); + + --checkbox-bg-color: var(--contrast-10); + --checkbox-checked-bg-color: var(--primary-color); + --checkbox-disabled-bg-color: var(--contrast-30); + --checkbox-border-color: var(--border-color); + --checkbox-icon-color: #fff; + + --switch-bg-color: var(--contrast-10); + --switch-border-color: var(--border-color); + --switch-toggle-color: var(--text-color); +} + +:root { + --btn-bg-color: var(--contrast-5); + --btn-hover-bg-color: var(--contrast-20); + --btn-border-color: var(--border-color); + --btn-text-color: var(--text-color); + --btn-icon-color: var(--icon-color); + --btn-font-weight: 400; + --btn-box-shadow: var(--box-shadow-xs); + + --btn-primary-bg-color: var(--primary-color); + --btn-primary-hover-bg-color: var(--primary-color-highlight); + --btn-primary-text-color: var(--contrast-text-color); + + --btn-success-bg-color: var(--success-color); + --btn-success-hover-bg-color: var(--success-color-highlight); + --btn-success-text-color: var(--contrast-text-color); + + --btn-error-bg-color: var(--error-color); + --btn-error-hover-bg-color: var(--error-color-highlight); + --btn-error-text-color: var(--contrast-text-color); + + --btn-link-text-color: var(--link-color); + --btn-link-hover-text-color: var(--link-color); +} + +:root { + --modal-overlay-bg-color: hsla(229, 21%, 16%, 0.55); + --modal-container-bg-color: hsl(241, 20%, 20%); + --modal-container-border-color: var(--contrast-30); + --modal-border-radius: var(--border-radius-lg); + --modal-box-shadow: none; +} + +:root { + --menu-bg-color: hsl(241, 20%, 20%); + --menu-border-color: var(--contrast-30); + --menu-border-radius: var(--border-radius); + --menu-box-shadow: none; + --menu-item-color: var(--text-color); + --menu-item-hover-color: var(--text-color); + --menu-item-bg-color: transparent; + --menu-item-hover-bg-color: var(--contrast-20); +} + +:root { + --tab-color: var(--text-color); + --tab-hover-color: var(--primary-text-color); + --tab-active-color: var(--primary-text-color); + --tab-highlight-color: var(--primary-text-color); +} + +:root { + --bookmark-title-color: var(--primary-text-color); + --bookmark-title-weight: 500; + --bookmark-description-color: var(--text-color); + --bookmark-description-weight: 400; + --bookmark-actions-color: var(--secondary-text-color); + --bookmark-actions-hover-color: var(--text-color); + --bookmark-actions-weight: 400; + --bulk-actions-bg-color: var(--contrast-5); +} \ No newline at end of file diff --git a/bookmarks/styles/theme-dark.scss b/bookmarks/styles/theme-dark.scss deleted file mode 100644 index ea1653d..0000000 --- a/bookmarks/styles/theme-dark.scss +++ /dev/null @@ -1,66 +0,0 @@ -// Import custom variables -@import "variables-dark"; - -// Import Spectre CSS lib -@import "spectre"; - -// Import style modules -@import "base"; -@import "responsive"; -@import "bookmark-details"; -@import "bookmark-page"; -@import "bookmark-form"; -@import "settings"; -@import "markdown"; -@import "reader-mode"; - -/* Dark theme overrides */ - -// Buttons -.btn.btn-primary { - background: $dt-primary-button-color; - border-color: darken($dt-primary-button-color, 5%); - - &:hover, &:active, &:focus { - background: darken($dt-primary-button-color, 5%); - border-color: darken($dt-primary-button-color, 10%); - } -} - -// Focus ring -a:focus, .btn:focus { - box-shadow: 0 0 0 .1rem rgba($primary-color, .5); -} - -// Forms -.form-input:not(:placeholder-shown):invalid, -.form-input:not(:placeholder-shown):invalid:focus, -.has-error .form-input, -.form-input.is-error, -.has-error .form-select, -.form-select.is-error { - background: darken($error-color, 40%); -} - -.form-checkbox input:checked + .form-icon, .form-radio input:checked + .form-icon, .form-switch input:checked + .form-icon { - background: $dt-primary-input-color; - border-color: $dt-primary-input-color; -} - -.form-switch .form-icon::before, .form-switch input:active + .form-icon::before { - background: $light-color; -} - -.form-switch input:checked + .form-icon { - background: $dt-primary-input-color; - border-color: $dt-primary-input-color; -} - -.form-radio input:checked + .form-icon::before { - background: $light-color; -} - -// Pagination -.pagination .page-item.active a { - background: $dt-primary-button-color; -} diff --git a/bookmarks/styles/theme-light.css b/bookmarks/styles/theme-light.css new file mode 100644 index 0000000..57a5cd9 --- /dev/null +++ b/bookmarks/styles/theme-light.css @@ -0,0 +1,30 @@ +@import "theme/variables.css"; +@import "theme/_normalize.css"; +@import "theme/base.css"; +@import "theme/typography.css"; +@import "theme/asian.css"; +@import "theme/tables.css"; +@import "theme/buttons.css"; +@import "theme/forms.css"; +@import "theme/code.css"; +@import "theme/dropdowns.css"; +@import "theme/menus.css"; +@import "theme/badges.css"; +@import "theme/empty.css"; +@import "theme/modals.css"; +@import "theme/pagination.css"; +@import "theme/tabs.css"; +@import "theme/toasts.css"; +@import "theme/autocomplete.css"; +@import "theme/animations.css"; +@import "theme/utilities.css"; + +@import "responsive.css"; +@import "layout.css"; +@import "components.css"; +@import "bookmark-details.css"; +@import "bookmark-form.css"; +@import "bookmark-page.css"; +@import "markdown.css"; +@import "reader-mode.css"; +@import "settings.css"; diff --git a/bookmarks/styles/theme-light.scss b/bookmarks/styles/theme-light.scss deleted file mode 100644 index bf5ac01..0000000 --- a/bookmarks/styles/theme-light.scss +++ /dev/null @@ -1,15 +0,0 @@ -// Import custom variables -@import "variables-light"; - -// Import Spectre CSS lib -@import "spectre"; - -// Import style modules -@import "base"; -@import "responsive"; -@import "bookmark-details"; -@import "bookmark-page"; -@import "bookmark-form"; -@import "settings"; -@import "markdown"; -@import "reader-mode"; diff --git a/bookmarks/styles/theme/LICENSE b/bookmarks/styles/theme/LICENSE new file mode 100644 index 0000000..7d4eb70 --- /dev/null +++ b/bookmarks/styles/theme/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2016 - 2020 Yan Zhu + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/bookmarks/styles/theme/_normalize.css b/bookmarks/styles/theme/_normalize.css new file mode 100644 index 0000000..db945bd --- /dev/null +++ b/bookmarks/styles/theme/_normalize.css @@ -0,0 +1,446 @@ +/* Manually forked from Normalize.css */ +/* normalize.css v5.0.0 | MIT License | github.com/necolas/normalize.css */ + +/** + * 1. Change the default font family in all browsers (opinionated). + * 2. Correct the line height in all browsers. + * 3. Prevent adjustments of font size after orientation changes in + * IE on Windows Phone and in iOS. + */ + +/* Document + ========================================================================== */ + +html { + font-family: sans-serif; /* 1 */ + -ms-text-size-adjust: 100%; /* 3 */ + -webkit-text-size-adjust: 100%; /* 3 */ +} + +/* Sections + ========================================================================== */ + +/** + * Remove the margin in all browsers (opinionated). + */ + +body { + margin: 0; +} + +/** + * Add the correct display in IE 9-. + */ + +article, +aside, +footer, +header, +nav, +section { + display: block; +} + +/** + * Correct the font size and margin on `h1` elements within `section` and + * `article` contexts in Chrome, Firefox, and Safari. + */ + +h1 { + font-size: 2em; + margin: 0.67em 0; +} + +/* Grouping content + ========================================================================== */ + +/** + * Add the correct display in IE 9-. + * 1. Add the correct display in IE. + */ + +figcaption, +figure, +main { /* 1 */ + display: block; +} + +/** + * Add the correct margin in IE 8 (removed). + */ + +/** + * 1. Add the correct box sizing in Firefox. + * 2. Show the overflow in Edge and IE. + */ + +hr { + box-sizing: content-box; /* 1 */ + height: 0; /* 1 */ + overflow: visible; /* 2 */ +} + +/** + * 1. Correct the inheritance and scaling of font size in all browsers. (removed) + * 2. Correct the odd `em` font sizing in all browsers. + */ + +/* Text-level semantics + ========================================================================== */ + +/** + * 1. Remove the gray background on active links in IE 10. + * 2. Remove gaps in links underline in iOS 8+ and Safari 8+. + */ + +a { + background-color: transparent; /* 1 */ + -webkit-text-decoration-skip: objects; /* 2 */ +} + +/** + * Remove the outline on focused links when they are also active or hovered + * in all browsers (opinionated). + */ + +a:active, +a:hover { + outline-width: 0; +} + +/** + * Modify default styling of address. + */ + +address { + font-style: normal; +} + +/** + * 1. Remove the bottom border in Firefox 39-. + * 2. Add the correct text decoration in Chrome, Edge, IE, Opera, and Safari. (removed) + */ + +/** + * Prevent the duplicate application of `bolder` by the next rule in Safari 6. + */ + +b, +strong { + font-weight: inherit; +} + +/** + * Add the correct font weight in Chrome, Edge, and Safari. + */ + +b, +strong { + font-weight: bolder; +} + +/** + * 1. Correct the inheritance and scaling of font size in all browsers. + * 2. Correct the odd `em` font sizing in all browsers. + */ + +code, +kbd, +pre, +samp { + font-family: var(--mono-font-family); /* 1 (changed) */ + font-size: 1em; /* 2 */ +} + +/** + * Add the correct font style in Android 4.3-. + */ + +dfn { + font-style: italic; +} + +/** + * Add the correct background and color in IE 9-. (Removed) + */ + +/** + * Add the correct font size in all browsers. + */ + +small { + font-size: 80%; + font-weight: 400; /* (added) */ +} + +/** + * Prevent `sub` and `sup` elements from affecting the line height in + * all browsers. + */ + +sub, +sup { + font-size: 75%; + line-height: 0; + position: relative; + vertical-align: baseline; +} + +sub { + bottom: -0.25em; +} + +sup { + top: -0.5em; +} + +/* Embedded content + ========================================================================== */ + +/** + * Add the correct display in IE 9-. + */ + +audio, +video { + display: inline-block; +} + +/** + * Add the correct display in iOS 4-7. + */ + +audio:not([controls]) { + display: none; + height: 0; +} + +/** + * Remove the border on images inside links in IE 10-. + */ + +img { + border-style: none; +} + +/** + * Hide the overflow in IE. + */ + +svg:not(:root) { + overflow: hidden; +} + +/* Forms + ========================================================================== */ + +/** + * 1. Change the font styles in all browsers (opinionated). + * 2. Remove the margin in Firefox and Safari. + */ + +button, +input, +optgroup, +select, +textarea { + font-family: inherit; /* 1 (changed) */ + font-size: inherit; /* 1 (changed) */ + line-height: inherit; /* 1 (changed) */ + margin: 0; /* 2 */ +} + +/** + * Show the overflow in IE. + * 1. Show the overflow in Edge. + */ + +button, +input { /* 1 */ + overflow: visible; +} + +/** + * Remove the inheritance of text transform in Edge, Firefox, and IE. + * 1. Remove the inheritance of text transform in Firefox. + */ + +button, +select { /* 1 */ + text-transform: none; +} + +/** + * 1. Prevent a WebKit bug where (2) destroys native `audio` and `video` + * controls in Android 4. + * 2. Correct the inability to style clickable types in iOS and Safari. + */ + +button, +html [type="button"], /* 1 */ +[type="reset"], +[type="submit"] { + -webkit-appearance: button; /* 2 */ +} + +/** + * Remove the inner border and padding in Firefox. + */ + +button::-moz-focus-inner, +[type="button"]::-moz-focus-inner, +[type="reset"]::-moz-focus-inner, +[type="submit"]::-moz-focus-inner { + border-style: none; + padding: 0; +} + +/** + * Restore the focus styles unset by the previous rule (removed). + */ + + +/** + * Change the border, margin, and padding in all browsers (opinionated) (changed). + */ + +fieldset { + border: 0; + margin: 0; + padding: 0; +} + +/** + * 1. Correct the text wrapping in Edge and IE. + * 2. Correct the color inheritance from `fieldset` elements in IE. + * 3. Remove the padding so developers are not caught out when they zero out + * `fieldset` elements in all browsers. + */ + +legend { + box-sizing: border-box; /* 1 */ + color: inherit; /* 2 */ + display: table; /* 1 */ + max-width: 100%; /* 1 */ + padding: 0; /* 3 */ + white-space: normal; /* 1 */ +} + +/** + * 1. Add the correct display in IE 9-. + * 2. Add the correct vertical alignment in Chrome, Firefox, and Opera. + */ + +progress { + display: inline-block; /* 1 */ + vertical-align: baseline; /* 2 */ +} + +/** + * Remove the default vertical scrollbar in IE. + */ + +textarea { + overflow: auto; +} + +/** + * 1. Add the correct box sizing in IE 10-. + * 2. Remove the padding in IE 10-. + */ + +[type="checkbox"], +[type="radio"] { + box-sizing: border-box; /* 1 */ + padding: 0; /* 2 */ +} + +/** + * Correct the cursor style of increment and decrement buttons in Chrome. + */ + +[type="number"]::-webkit-inner-spin-button, +[type="number"]::-webkit-outer-spin-button { + height: auto; +} + +/** + * 1. Correct the odd appearance in Chrome and Safari. + * 2. Correct the outline style in Safari. + */ + +[type="search"] { + -webkit-appearance: textfield; /* 1 */ + outline-offset: -2px; /* 2 */ +} + +/** + * Remove the inner padding and cancel buttons in Chrome and Safari on macOS. + */ + +[type="search"]::-webkit-search-cancel-button, +[type="search"]::-webkit-search-decoration { + -webkit-appearance: none; +} + +/** + * 1. Correct the inability to style clickable types in iOS and Safari. + * 2. Change font properties to `inherit` in Safari. + */ + +::-webkit-file-upload-button { + -webkit-appearance: button; /* 1 */ + font: inherit; /* 2 */ +} + +/* Interactive + ========================================================================== */ + +/* + * Add the correct display in IE 9-. + * 1. Add the correct display in Edge, IE, and Firefox. + */ + +details, /* 1 */ +menu { + display: block; +} + +/* + * Add the correct display in all browsers. + */ + +summary { + display: list-item; + outline: none; +} + +/* Scripting + ========================================================================== */ + +/** + * Add the correct display in IE 9-. + */ + +canvas { + display: inline-block; +} + +/** + * Add the correct display in IE. + */ + +template { + display: none; +} + +/* Hidden + ========================================================================== */ + +/** + * Add the correct display in IE 10-. + */ + +[hidden] { + display: none; +} diff --git a/bookmarks/styles/theme/animations.css b/bookmarks/styles/theme/animations.css new file mode 100644 index 0000000..5366376 --- /dev/null +++ b/bookmarks/styles/theme/animations.css @@ -0,0 +1,38 @@ +/* Animations */ +@keyframes loading { + 0% { + transform: rotate(0deg); + } + 100% { + transform: rotate(360deg); + } +} + +@keyframes slide-down { + 0% { + opacity: 0; + transform: translateY(calc(-1 * var(--unit-8))); + } + 100% { + opacity: 1; + transform: translateY(0); + } +} + +@keyframes fade-in { + 0% { + opacity: 0; + } + 100% { + opacity: 1; + } +} + +@keyframes fade-out { + 0% { + opacity: 1; + } + 100% { + opacity: 0; + } +} diff --git a/bookmarks/styles/theme/asian.css b/bookmarks/styles/theme/asian.css new file mode 100644 index 0000000..537884c --- /dev/null +++ b/bookmarks/styles/theme/asian.css @@ -0,0 +1,43 @@ +/* Optimized for East Asian CJK */ +html:lang(zh), +html:lang(zh-Hans), +.lang-zh, +.lang-zh-hans { + font-family: var(--cjk-zh-hans-font-family); +} + +html:lang(zh-Hant), +.lang-zh-hant { + font-family: var(--cjk-zh-hant-font-family); +} + +html:lang(ja), +.lang-ja { + font-family: var(--cjk-jp-font-family); +} + +html:lang(ko), +.lang-ko { + font-family: var(--cjk-ko-font-family); +} + +:lang(zh), +:lang(ja), +.lang-cjk { + & ins, + & u { + border-bottom: var(--border-width) solid; + text-decoration: none; + } + + & del + del, + & del + s, + & ins + ins, + & ins + u, + & s + del, + & s + s, + & u + ins, + & u + u { + margin-left: .125em; + } +} diff --git a/bookmarks/styles/theme/autocomplete.css b/bookmarks/styles/theme/autocomplete.css new file mode 100644 index 0000000..7ab2b21 --- /dev/null +++ b/bookmarks/styles/theme/autocomplete.css @@ -0,0 +1,55 @@ +/* Autocomplete */ +.form-autocomplete { + position: relative; + + & .form-autocomplete-input { + align-content: flex-start; + display: flex; + flex-wrap: wrap; + height: auto; + min-height: var(--unit-8); + padding: var(--unit-h); + background: var(--input-bg-color); + + &.is-focused { + outline: var(--focus-outline); + outline-offset: calc(var(--focus-outline-offset) * -1); + } + + & .form-input { + background: transparent; + border-color: transparent; + box-shadow: none; + display: inline-block; + flex: 1 0 auto; + height: var(--unit-6); + line-height: var(--unit-4); + margin: var(--unit-h); + width: auto; + + &:focus { + outline: none; + } + } + } + + & .menu { + left: 0; + position: absolute; + top: 100%; + width: 100%; + + & .menu-item.selected > a, & .menu-item > a:hover { + background: var(--menu-item-hover-bg-color); + color: var(--menu-item-hover-color); + } + + & .group-item, & .group-item:hover { + color: var(--tertiary-text-color); + text-transform: uppercase; + background: none; + font-size: 0.6rem; + font-weight: bold; + } + } +} \ No newline at end of file diff --git a/bookmarks/styles/theme/badges.css b/bookmarks/styles/theme/badges.css new file mode 100644 index 0000000..4657cfc --- /dev/null +++ b/bookmarks/styles/theme/badges.css @@ -0,0 +1,64 @@ +/* Badges */ +.badge { + position: relative; + white-space: nowrap; + + &[data-badge], + &:not([data-badge]) { + &::after { + background: var(--primary-color); + background-clip: padding-box; + border-radius: .5rem; + box-shadow: 0 0 0 1px var(--body-color); + color: var(--contrast-text-color); + content: attr(data-badge); + display: inline-block; + transform: translate(-.05rem, -.5rem); + } + } + + &[data-badge] { + &::after { + font-size: var(--font-size-sm); + height: .9rem; + line-height: 1; + min-width: .9rem; + padding: .1rem .2rem; + text-align: center; + white-space: nowrap; + } + } + + &:not([data-badge]), + &[data-badge=""] { + &::after { + height: 6px; + min-width: 6px; + padding: 0; + width: 6px; + } + } + + /* Badges for Buttons */ + + &.btn { + &::after { + position: absolute; + top: 0; + right: 0; + transform: translate(50%, -50%); + } + } + + /* Badges for Avatars */ + + &.avatar { + &::after { + position: absolute; + top: 14.64%; + right: 14.64%; + transform: translate(50%, -50%); + z-index: var(--zindex-1); + } + } +} diff --git a/bookmarks/styles/theme/base.css b/bookmarks/styles/theme/base.css new file mode 100644 index 0000000..b6ec74d --- /dev/null +++ b/bookmarks/styles/theme/base.css @@ -0,0 +1,61 @@ +/* Base */ +*, +*::before, +*::after { + box-sizing: inherit; +} + +html { + box-sizing: border-box; + font-size: var(--html-font-size); + line-height: var(--html-line-height); + -webkit-tap-highlight-color: transparent; + scrollbar-gutter: stable; +} + +/* Reserve space for vert. scrollbar to avoid layout shifting when scrollbars are added */ +html { + scrollbar-gutter: stable; +} + +@media (pointer: coarse) { + html { + scrollbar-gutter: initial; + } +} + +body { + background: var(--body-color); + color: var(--text-color); + font-family: var(--body-font-family); + font-size: var(--font-size); + overflow-x: hidden; + text-rendering: optimizeLegibility; +} + +a { + color: var(--link-color); + outline: none; + text-decoration: none; +} + +a:focus-visible { + outline: var(--focus-outline); + outline-offset: var(--focus-outline-offset); +} + +a:focus, +a:hover, +a:active, +a.active { + text-decoration: underline; +} + +summary { + cursor: pointer; +} + +summary:focus-visible { + outline: var(--focus-outline); + outline-offset: var(--focus-outline-offset); +} diff --git a/bookmarks/styles/theme/buttons.css b/bookmarks/styles/theme/buttons.css new file mode 100644 index 0000000..77959e4 --- /dev/null +++ b/bookmarks/styles/theme/buttons.css @@ -0,0 +1,257 @@ +/* Buttons */ +:root { + --btn-bg-color: var(--body-color); + --btn-hover-bg-color: var(--gray-50); + --btn-border-color: var(--border-color); + --btn-text-color: var(--text-color); + --btn-icon-color: var(--icon-color); + --btn-font-weight: 400; + --btn-box-shadow: var(--box-shadow-xs); + + --btn-primary-bg-color: var(--primary-color); + --btn-primary-hover-bg-color: var(--primary-color-highlight); + --btn-primary-text-color: var(--contrast-text-color); + + --btn-success-bg-color: var(--success-color); + --btn-success-hover-bg-color: var(--success-color-highlight); + --btn-success-text-color: var(--contrast-text-color); + + --btn-error-bg-color: var(--error-color); + --btn-error-hover-bg-color: var(--error-color-highlight); + --btn-error-text-color: var(--contrast-text-color); + + --btn-link-text-color: var(--link-color); + --btn-link-hover-text-color: var(--link-color); +} + +.btn { + appearance: none; + background: var(--btn-bg-color); + border: var(--border-width) solid var(--btn-border-color); + border-radius: var(--border-radius); + color: var(--btn-text-color); + font-weight: var(--btn-font-weight); + cursor: pointer; + display: inline-flex; + align-items: baseline; + justify-content: center; + font-size: var(--font-size); + height: var(--control-size); + line-height: var(--line-height); + outline: none; + padding: var(--control-padding-y) var(--control-padding-x); + box-shadow: var(--btn-box-shadow); + text-align: center; + text-decoration: none; + transition: background 0.2s, border 0.2s, box-shadow 0.2s, color 0.2s; + user-select: none; + vertical-align: middle; + white-space: nowrap; + + &:focus-visible { + outline: var(--focus-outline); + outline-offset: var(--focus-outline-offset); + } + + &:hover { + background: var(--btn-hover-bg-color); + text-decoration: none; + } + + &[disabled], + &:disabled, + &.disabled { + cursor: default; + opacity: 0.5; + pointer-events: none; + } + + &:focus, + &:hover, + &:active, + &.active { + text-decoration: none; + } + + /* Button Primary */ + + &.btn-primary { + background: var(--btn-primary-bg-color); + border-color: transparent; + color: var(--btn-primary-text-color); + --btn-icon-color: var(--btn-primary-text-color); + + &:hover { + background: var(--btn-primary-hover-bg-color); + } + } + + /* Button Colors */ + + &.btn-success { + background: var(--btn-success-bg-color); + border-color: transparent; + color: var(--btn-success-text-color); + --btn-icon-color: var(--btn-success-text-color); + + &:hover { + background: var(--btn-success-hover-bg-color); + } + } + + &.btn-error { + --btn-border-color: var(--error-color); + --btn-text-color: var(--error-color); + + &:hover { + --btn-hover-bg-color: var(--error-color-shade); + } + } + + /* Button Link */ + + &.btn-link { + background: transparent; + border-color: transparent; + box-shadow: none; + color: var(--btn-link-text-color); + --btn-icon-color: var(--btn-link-text-color); + + &:hover { + color: var(--btn-link-hover-text-color); + --btn-icon-color: var(--btn-link-hover-text-color); + } + + &:focus, + &:hover, + &:active, + &.active { + text-decoration: none; + } + } + + /* Button Sizes */ + + &.btn-sm { + font-size: var(--font-size-sm); + height: var(--control-size-sm); + padding: var(--control-padding-y-sm) var(--control-padding-x-sm); + } + + &.btn-lg { + font-size: var(--font-size-lg); + height: var(--control-size-lg); + padding: var(--control-padding-y-lg) var(--control-padding-x-lg); + } + + /* Button Block */ + + &.btn-block { + display: block; + width: 100%; + } + + /* Button Action */ + + &.btn-action { + width: var(--control-size); + padding-left: 0; + padding-right: 0; + + &.btn-sm { + width: var(--control-size-sm); + } + + &.btn-lg { + width: var(--control-size-lg); + } + } + + /* Button Clear */ + + &.btn-clear { + background: transparent; + border: 0; + color: currentColor; + box-shadow: none; + height: var(--unit-5); + line-height: var(--unit-4); + margin-left: var(--unit-1); + margin-right: -2px; + opacity: 1; + padding: var(--unit-h); + text-decoration: none; + width: var(--unit-5); + + &::before { + content: "\2715"; + } + } + + /* Wider button */ + + &.btn-wide { + padding-left: var(--unit-6); + padding-right: var(--unit-6); + } + + /* Small icon button */ + + &.btn-sm.btn-icon { + display: inline-flex; + align-items: baseline; + gap: var(--unit-h); + + svg { + align-self: center; + } + } + + /* Button icons */ + + & svg { + color: var(--btn-icon-color); + align-self: center; + } +} + +/* Button groups */ +.btn-group { + display: inline-flex; + flex-wrap: wrap; + + .btn { + flex: 1 0 auto; + + &:first-child:not(:last-child) { + border-bottom-right-radius: 0; + border-top-right-radius: 0; + } + + &:not(:first-child):not(:last-child) { + border-radius: 0; + margin-left: calc(-1 * var(--border-width)); + } + + &:last-child:not(:first-child) { + border-bottom-left-radius: 0; + border-top-left-radius: 0; + margin-left: calc(-1 * var(--border-width)); + } + + &:focus, + &:hover, + &:active, + &.active { + z-index: var(--zindex-0); + } + } + + &.btn-group-block { + display: flex; + + .btn { + flex: 1 0 0; + } + } +} \ No newline at end of file diff --git a/bookmarks/styles/theme/code.css b/bookmarks/styles/theme/code.css new file mode 100644 index 0000000..326d32d --- /dev/null +++ b/bookmarks/styles/theme/code.css @@ -0,0 +1,30 @@ +/* Code */ +:root { + --code-bg-color: var(--body-color-contrast); + --code-color: var(--text-color); +} + +code { + border-radius: var(--border-radius); + line-height: 1.25; + padding: .1rem .2rem; + background: var(--code-bg-color); + color: var(--code-color); + font-size: 85%; +} + +.code { + border-radius: var(--border-radius); + background: var(--code-bg-color); + color: var(--text-color); + position: relative; + + & code { + color: inherit; + display: block; + line-height: 1.5; + overflow-x: auto; + padding: var(--unit-2); + width: 100%; + } +} diff --git a/bookmarks/styles/theme/dropdowns.css b/bookmarks/styles/theme/dropdowns.css new file mode 100644 index 0000000..d421f68 --- /dev/null +++ b/bookmarks/styles/theme/dropdowns.css @@ -0,0 +1,36 @@ +/* Dropdown */ +.dropdown { + display: inline-block; + position: relative; + + .menu { + animation: fade-in .15s ease 1; + display: none; + left: 0; + max-height: 50vh; + overflow-y: auto; + position: absolute; + top: 100%; + } + + &.dropdown-right { + .menu { + left: auto; + right: 0; + } + } + + &.active .menu, + .dropdown-toggle:focus + .menu, + .menu:hover { + display: block; + } + + /* Fix dropdown-toggle border radius in button groups */ + .btn-group { + .dropdown-toggle:nth-last-child(2) { + border-bottom-right-radius: var(--border-radius); + border-top-right-radius: var(--border-radius); + } + } +} diff --git a/bookmarks/styles/theme/empty.css b/bookmarks/styles/theme/empty.css new file mode 100644 index 0000000..611e476 --- /dev/null +++ b/bookmarks/styles/theme/empty.css @@ -0,0 +1,21 @@ +/* Empty states (or Blank slates) */ +.empty { + background: var(--body-color-contrast); + border-radius: var(--border-radius); + color: var(--secondary-text-color); + text-align: center; + padding: var(--unit-16) var(--unit-8); + + .empty-icon { + margin-bottom: var(--layout-spacing-lg); + } + + .empty-title, + .empty-subtitle { + margin: var(--layout-spacing) auto; + } + + .empty-action { + margin-top: var(--layout-spacing-lg); + } +} diff --git a/bookmarks/styles/theme/forms.css b/bookmarks/styles/theme/forms.css new file mode 100644 index 0000000..a3eebb1 --- /dev/null +++ b/bookmarks/styles/theme/forms.css @@ -0,0 +1,515 @@ +/* Forms */ +:root { + --input-bg-color: var(--body-color); + --input-disabled-bg-color: var(--gray-100); + --input-text-color: var(--text-color); + --input-hint-color: var(--secondary-text-color); + --input-border-color: var(--border-color); + --input-placeholder-color: var(--tertiary-text-color); + --input-box-shadow: var(--box-shadow-xs); + + --checkbox-bg-color: var(--body-color); + --checkbox-checked-bg-color: var(--primary-color); + --checkbox-disabled-bg-color: var(--gray-100); + --checkbox-border-color: var(--border-color); + --checkbox-icon-color: #fff; + + --switch-bg-color: var(--gray-300); + --switch-border-color: var(--gray-400); + --switch-toggle-color: #fff; +} + +.form-group { + &:first-of-type { + margin-top: var(--unit-4); + } + &:not(:last-child) { + margin-bottom: var(--unit-4); + } +} + +fieldset { + margin-bottom: var(--layout-spacing-lg); +} + +legend { + font-size: var(--font-size-lg); + font-weight: 500; + margin-bottom: var(--layout-spacing-lg); +} + +/* Form element: Label */ +.form-label { + display: block; + line-height: var(--line-height); + margin-bottom: var(--unit-2); + font-weight: 500; +} + +details summary .form-label { + margin-bottom: 0; +} + +details[open] summary .form-label { + margin-bottom: var(--unit-2); +} + +/* Form element: Input */ +.form-input { + appearance: none; + background: var(--input-bg-color); + background-image: none; + border: var(--border-width) solid var(--input-border-color); + border-radius: var(--border-radius); + box-shadow: var(--input-box-shadow); + color: var(--input-text-color); + display: block; + font-size: var(--font-size); + height: var(--control-size); + line-height: var(--line-height); + max-width: 100%; + outline: none; + padding: var(--control-padding-y) var(--control-padding-x); + position: relative; + transition: background 0.2s, border 0.2s, color 0.2s; + width: 100%; + + &:focus { + outline: var(--focus-outline); + outline-offset: calc(var(--focus-outline-offset) * -1); + } + + &::placeholder { + color: var(--input-placeholder-color); + opacity: 1; + } + + /* Input sizes */ + + &.input-sm { + font-size: var(--font-size-sm); + height: var(--control-size-sm); + padding: var(--control-padding-y-sm) var(--control-padding-x-sm); + } + + &.input-lg { + font-size: var(--font-size-lg); + height: var(--control-size-lg); + padding: var(--control-padding-y-lg) var(--control-padding-x-lg); + } + + &.input-inline { + display: inline-block; + vertical-align: middle; + width: auto; + } + + /* Input types */ + + &[type="file"] { + height: auto; + } +} + +/* Form element: Textarea */ +textarea.form-input { + &, + &.input-lg, + &.input-sm { + height: auto; + } +} + +/* Form element: Input hint */ +.form-input-hint { + color: var(--input-hint-color); + font-size: var(--font-size-sm); + margin-top: var(--unit-1); + + .has-success &, + .is-success + & { + color: var(--success-color); + } + + .has-error &, + .is-error + & { + color: var(--error-color); + } +} + +/* Form element: Select */ +.form-select { + appearance: none; + background: var(--input-bg-color); + border: var(--border-width) solid var(--input-border-color); + border-radius: var(--border-radius); + box-shadow: var(--input-box-shadow); + color: var(--input-text-color); + font-size: var(--font-size); + height: var(--control-size); + line-height: var(--line-height); + outline: none; + padding: var(--control-padding-y) var(--control-padding-x); + vertical-align: middle; + width: 100%; + + &:focus { + outline: var(--focus-outline); + outline-offset: calc(var(--focus-outline-offset) * -1); + } + + /* Select sizes */ + + &.select-sm { + font-size: var(--font-size-sm); + height: var(--control-size-sm); + padding: var(--control-padding-y-sm) calc(var(--control-icon-size) + var(--control-padding-x-sm)) var(--control-padding-y-sm) var(--control-padding-x-sm); + } + + &.select-lg { + font-size: var(--font-size-lg); + height: var(--control-size-lg); + padding: var(--control-padding-y-lg) calc(var(--control-icon-size) + var(--control-padding-x-lg)) var(--control-padding-y-lg) var(--control-padding-x-lg); + } + + /* Multiple select */ + + &[size], + &[multiple] { + height: auto; + padding: var(--control-padding-y) var(--control-padding-x); + + & option { + padding: var(--unit-h) var(--unit-1); + } + } + + &:not([multiple]):not([size]) { + background: var(--input-bg-color) url("data:image/svg+xml;charset=utf8,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%204%205'%3E%3Cpath%20fill='%23667189'%20d='M2%200L0%202h4zm0%205L0%203h4z'/%3E%3C/svg%3E") no-repeat right .35rem center / .4rem .5rem; + padding-right: calc(var(--control-icon-size) + var(--control-padding-x)); + } +} + +/* Form element: Checkbox and Radio */ +.form-checkbox, +.form-radio, +.form-switch { + display: block; + line-height: var(--line-height); + margin: calc((var(--control-size) - var(--control-size-sm)) / 2) 0; + min-height: var(--control-size-sm); + padding: calc((var(--control-size-sm) - var(--line-height)) / 2) var(--control-padding-x) calc((var(--control-size-sm) - var(--line-height)) / 2) calc(var(--control-icon-size) + var(--control-padding-x)); + position: relative; + + input { + clip: rect(0, 0, 0, 0); + height: 1px; + margin: -1px; + overflow: hidden; + position: absolute; + width: 1px; + + &:focus-visible + .form-icon { + outline: var(--focus-outline); + outline-offset: var(--focus-outline-offset); + } + + &:checked + .form-icon { + background: var(--checkbox-checked-bg-color); + border-color: var(--checkbox-checked-bg-color); + } + } + + .form-icon { + border: var(--border-width) solid var(--checkbox-border-color); + box-shadow: var(--input-box-shadow); + cursor: pointer; + display: inline-block; + position: absolute; + transition: background .2s, border .2s, color .2s; + } + + /* Input checkbox, radio, and switch sizes */ + + &.input-sm { + font-size: var(--font-size-sm); + margin: 0; + } + + &.input-lg { + font-size: var(--font-size-lg); + margin: calc((var(--control-size-lg) - var(--control-size-sm)) / 2) 0; + } +} + +.form-checkbox, +.form-radio { + .form-icon { + background: var(--checkbox-bg-color); + height: var(--control-icon-size); + left: 0; + top: calc((var(--control-size-sm) - var(--control-icon-size)) / 2); + width: var(--control-icon-size); + } +} + +.form-checkbox { + font-weight: 500; + + .form-icon { + border-radius: var(--border-radius); + } + + input { + &:checked + .form-icon { + &::before { + background-clip: padding-box; + border: var(--border-width-lg) solid var(--checkbox-icon-color); + border-left-width: 0; + border-top-width: 0; + content: ""; + height: 9px; + left: 50%; + margin-left: -3px; + margin-top: -6px; + position: absolute; + top: 50%; + transform: rotate(45deg); + width: 6px; + } + } + + &:indeterminate + .form-icon { + background: var(--checkbox-checked-bg-color); + border-color: var(--checkbox-checked-bg-color); + + &::before { + background: var(--checkbox-icon-color); + content: ""; + height: 2px; + left: 50%; + margin-left: -5px; + margin-top: -1px; + position: absolute; + top: 50%; + width: 10px; + } + } + } +} + +.form-radio { + .form-icon { + border-radius: 50%; + } + + input { + &:checked + .form-icon { + &::before { + background: var(--checkbox-icon-color); + border-radius: 50%; + content: ""; + height: 6px; + left: 50%; + position: absolute; + top: 50%; + transform: translate(-50%, -50%); + width: 6px; + } + } + } +} + +/* Form element: Switch */ +.form-switch { + padding-left: calc(var(--unit-8) + var(--control-padding-x)); + + .form-icon { + background: var(--switch-bg-color); + background-clip: padding-box; + border-color: var(--switch-border-color); + border-radius: calc(var(--unit-2) + var(--border-width)); + height: calc(var(--unit-4) + var(--border-width) * 2); + left: 0; + top: calc((var(--control-size-sm) - var(--unit-4)) / 2 - var(--border-width)); + width: var(--unit-8); + + &::before { + background: var(--switch-toggle-color); + border-radius: 50%; + content: ""; + display: block; + height: var(--unit-4); + left: 0; + position: absolute; + top: 0; + transition: background .2s, border .2s, color .2s, left .2s; + width: var(--unit-4); + } + } + + input { + &:checked + .form-icon { + &::before { + left: 14px; + } + } + } +} + +/* Form Icons */ +.has-icon-left, +.has-icon-right { + position: relative; + + .form-icon { + height: var(--control-icon-size); + margin: 0 var(--control-padding-y); + position: absolute; + top: 50%; + transform: translateY(-50%); + width: var(--control-icon-size); + z-index: calc(var(--zindex-0) + 1); + } +} + +.has-icon-left { + & .form-icon { + left: var(--border-width); + } + + & .form-input { + padding-left: calc(var(--control-icon-size) + var(--control-padding-y) * 2); + } +} + +.has-icon-right { + & .form-icon { + right: var(--border-width); + } + + & .form-input { + padding-right: calc(var(--control-icon-size) + var(--control-padding-y) * 2); + } +} + + +/* Form element: Input groups */ +.input-group { + display: flex; + + .input-group-addon { + background: var(--body-color); + border: var(--border-width) solid var(--input-border-color); + border-radius: var(--border-radius); + line-height: var(--line-height); + padding: var(--control-padding-y) var(--control-padding-x); + white-space: nowrap; + + &.addon-sm { + font-size: var(--font-size-sm); + padding: var(--control-padding-y-sm) var(--control-padding-x-sm); + } + + &.addon-lg { + font-size: var(--font-size-lg); + padding: var(--control-padding-y-lg) var(--control-padding-x-lg); + } + } + + .form-input, + .form-select { + flex: 1 1 auto; + width: 1%; + } + + .input-group-btn { + z-index: var(--zindex-0); + } + + .form-input, + .form-select, + .input-group-addon, + .input-group-btn { + &:first-child:not(:last-child) { + border-bottom-right-radius: 0; + border-top-right-radius: 0; + } + + &:not(:first-child):not(:last-child) { + border-radius: 0; + margin-left: calc(-1 * var(--border-width)); + } + + &:last-child:not(:first-child) { + border-bottom-left-radius: 0; + border-top-left-radius: 0; + margin-left: calc(-1 * var(--border-width)); + } + + &:focus { + z-index: calc(var(--zindex-0) + 1); + } + } + + .form-select { + width: auto; + } + + &.input-inline { + display: inline-flex; + } +} + +/* Form validation states */ +.form-input, +.form-select { + .has-success &, + &.is-success { + background: var(--success-color-shade); + border-color: var(--success-color); + + &:focus { + outline-color: var(--success-color); + } + } + + .has-error &, + &.is-error { + background: var(--error-color-shade); + border-color: var(--error-color); + + &:focus { + outline-color: var(--error-color); + } + } +} + +/* Form disabled and readonly */ +.form-input, +.form-select { + &:disabled, + &.disabled { + background-color: var(--input-disabled-bg-color); + cursor: not-allowed; + } +} + +input { + &:disabled, + &.disabled { + & + .form-icon { + background: var(--checkbox-disabled-bg-color); + cursor: not-allowed; + } + } +} + +/* Increase input font size on small viewports to prevent zooming on focus the input */ +/* on mobile devices. 430px relates to the "normalized" iPhone 14 Pro Max */ +/* viewport size */ +@media screen and (max-width: 430px) { + .form-input { + font-size: 16px; + } +} diff --git a/bookmarks/styles/theme/menus.css b/bookmarks/styles/theme/menus.css new file mode 100644 index 0000000..61d2c96 --- /dev/null +++ b/bookmarks/styles/theme/menus.css @@ -0,0 +1,89 @@ +:root { + --menu-bg-color: var(--body-color); + --menu-border-color: var(--gray-200); + --menu-border-radius: var(--border-radius); + --menu-box-shadow: var(--box-shadow); + --menu-item-color: var(--text-color); + --menu-item-hover-color: var(--primary-text-color); + --menu-item-bg-color: transparent; + --menu-item-hover-bg-color: var(--primary-color-shade); +} + +/* Menus */ +.menu { + background: var(--menu-bg-color); + border: solid 1px var(--menu-border-color); + border-radius: var(--menu-border-radius); + box-shadow: var(--menu-box-shadow); + list-style: none; + margin: 0; + min-width: var(--control-width-xs); + transform: translateY(var(--layout-spacing-sm)); + z-index: var(--zindex-3); + + &.menu-nav { + background: transparent; + box-shadow: none; + } + + .menu-item { + margin-top: 0; + padding: 0 var(--unit-4); + position: relative; + text-decoration: none; + + &:first-of-type { + padding-top: var(--unit-2); + } + + &:last-of-type { + padding-bottom: var(--unit-2); + } + + & > a, .btn.btn-link { + border-radius: var(--menu-border-radius); + color: var(--menu-item-color); + background: var(--menu-item-bg-color); + display: block; + margin: 0 calc(-1 * var(--unit-2)); + padding: var(--unit-1) var(--unit-2); + text-decoration: none; + + &:focus, + &:hover, + &:active, + &.active { + background: var(--menu-item-hover-bg-color); + color: var(--menu-item-hover-color); + } + } + + .form-checkbox, + .form-radio, + .form-switch { + margin: var(--unit-h) 0; + } + + & + .menu-item { + margin-top: var(--unit-1); + } + } + + & .menu-badge { + align-items: center; + display: flex; + height: 100%; + position: absolute; + right: 0; + top: 0; + + .label { + margin-right: var(--unit-2); + } + } + + & .divider { + border-bottom: solid 1px var(--secondary-border-color); + margin: var(--unit-2) 0; + } +} \ No newline at end of file diff --git a/bookmarks/styles/theme/modals.css b/bookmarks/styles/theme/modals.css new file mode 100644 index 0000000..81b18e8 --- /dev/null +++ b/bookmarks/styles/theme/modals.css @@ -0,0 +1,93 @@ +/* Modals */ +:root { + --modal-overlay-bg-color: rgba(243, 244, 246, 0.6); + --modal-container-bg-color: var(--body-color); + --modal-container-border-color: var(--gray-200); + --modal-border-radius: var(--border-radius-lg); + --modal-box-shadow: var(--box-shadow-lg); +} + +.modal { + align-items: center; + bottom: 0; + display: none; + justify-content: center; + left: 0; + opacity: 0; + overflow: hidden; + padding: var(--layout-spacing); + position: fixed; + right: 0; + top: 0; + + &:target, + &.active { + display: flex; + opacity: 1; + z-index: var(--zindex-4); + + & .modal-overlay { + animation: fade-in .15s ease 1; + background: var(--modal-overlay-bg-color); + bottom: 0; + cursor: default; + display: block; + left: 0; + position: absolute; + right: 0; + top: 0; + } + + & .modal-container { + animation: fade-in .15s ease 1; + z-index: var(--zindex-0); + } + } + + &.active.closing { + & .modal-overlay, & .modal-container { + animation: fade-out .15s ease 1; + } + } +} + +.modal-container { + background: var(--modal-container-bg-color); + border: solid 1px var(--modal-container-border-color); + border-radius: var(--modal-border-radius); + box-shadow: var(--modal-box-shadow); + display: flex; + flex-direction: column; + gap: var(--unit-4); + max-height: 75vh; + max-width: var(--control-width-md); + padding: var(--unit-6); + width: 100%; + + & .modal-header { + color: var(--text-color); + + & button.close { + background: none; + border: none; + padding: 0; + line-height: 0; + cursor: pointer; + opacity: .85; + color: var(--secondary-text-color); + + &:hover { + opacity: 1; + } + } + } + + & .modal-body { + overflow-y: auto; + position: relative; + } + + & .modal-footer { + text-align: right; + } +} diff --git a/bookmarks/styles/theme/pagination.css b/bookmarks/styles/theme/pagination.css new file mode 100644 index 0000000..027ff37 --- /dev/null +++ b/bookmarks/styles/theme/pagination.css @@ -0,0 +1,61 @@ +/* Pagination */ +.pagination { + display: flex; + list-style: none; + margin: var(--unit-1) 0; + padding: var(--unit-1) 0; + + & .page-item { + margin: var(--unit-1) var(--unit-o); + + & span { + display: inline-block; + padding: var(--unit-1) var(--unit-1); + } + + & a { + border-radius: var(--border-radius); + display: inline-block; + padding: var(--unit-1) var(--unit-2); + text-decoration: none; + + &:focus, + &:hover { + color: var(--primary-text-color); + } + } + + &.disabled { + & a { + cursor: default; + opacity: .5; + pointer-events: none; + } + } + + &.active { + & a { + background: var(--primary-color); + color: var(--contrast-text-color); + } + } + + &.page-prev, + &.page-next { + flex: 1 0 50%; + } + + &.page-next { + text-align: right; + } + + & .page-item-title { + margin: 0; + } + + & .page-item-subtitle { + margin: 0; + opacity: .5; + } + } +} diff --git a/bookmarks/styles/theme/tables.css b/bookmarks/styles/theme/tables.css new file mode 100644 index 0000000..b9b2268 --- /dev/null +++ b/bookmarks/styles/theme/tables.css @@ -0,0 +1,26 @@ +/* Tables */ +.table { + border-collapse: collapse; + border-spacing: 0; + width: 100%; + text-align: left; + + /* Scrollable tables */ + + &.table-scroll { + display: block; + overflow-x: auto; + padding-bottom: 0.75rem; + white-space: nowrap; + } + + & td, + & th { + border-bottom: var(--border-width) solid var(--border-color); + padding: var(--unit-3) var(--unit-2); + } + + & th { + border-bottom-width: var(--border-width-lg); + } +} \ No newline at end of file diff --git a/bookmarks/styles/theme/tabs.css b/bookmarks/styles/theme/tabs.css new file mode 100644 index 0000000..c3570a3 --- /dev/null +++ b/bookmarks/styles/theme/tabs.css @@ -0,0 +1,75 @@ +/* Tabs */ +:root { + --tab-color: var(--text-color); + --tab-hover-color: var(--primary-text-color); + --tab-active-color: var(--primary-text-color); + --tab-highlight-color: var(--primary-color); +} + +.tab { + align-items: center; + border-bottom: var(--border-width) solid var(--border-color); + display: flex; + flex-wrap: wrap; + list-style: none; + margin: var(--unit-1) 0 calc(var(--unit-1) - var(--border-width)) 0; + + & .tab-item { + margin-top: 0; + + & a { + border-bottom: var(--border-width-lg) solid transparent; + color: var(--tab-color); + display: block; + margin: 0 var(--unit-2) 0 0; + padding: var(--unit-2) var(--unit-1) calc(var(--unit-2) - var(--border-width-lg)) var(--unit-1); + text-decoration: none; + + &:focus, + &:hover { + color: var(--tab-hover-color); + } + } + + &.active a, + & a.active { + border-bottom-color: var(--tab-highlight-color); + color: var(--tab-active-color); + } + + &.tab-action { + flex: 1 0 auto; + text-align: right; + } + + & .btn-clear { + margin-top: calc(-1 * var(--unit-1)); + } + } + + &.tab-block { + & .tab-item { + flex: 1 0 0; + text-align: center; + + & a { + margin: 0; + } + + & .badge { + &[data-badge]::after { + position: absolute; + right: var(--unit-h); + top: var(--unit-h); + transform: translate(0, 0); + } + } + } + } + + &:not(.tab-block) { + & .badge { + padding-right: 0; + } + } +} \ No newline at end of file diff --git a/bookmarks/styles/theme/toasts.css b/bookmarks/styles/theme/toasts.css new file mode 100644 index 0000000..6a35fcf --- /dev/null +++ b/bookmarks/styles/theme/toasts.css @@ -0,0 +1,35 @@ +/* Toasts */ +.toast { + background: var(--gray-600); + border-radius: var(--border-radius); + color: var(--contrast-text-color); + display: block; + padding: var(--layout-spacing); + width: 100%; + + &.toast-primary { + background: var(--primary-color); + } + + &.toast-success { + background: var(--success-color); + } + + &.toast-warning { + background: var(--warning-color); + } + + &.toast-error { + background: var(--error-color); + } + + .btn-clear { + margin: var(--unit-h); + } + + p { + &:last-child { + margin-bottom: 0; + } + } +} diff --git a/bookmarks/styles/theme/typography.css b/bookmarks/styles/theme/typography.css new file mode 100644 index 0000000..4688226 --- /dev/null +++ b/bookmarks/styles/theme/typography.css @@ -0,0 +1,117 @@ +/* Typography */ +/* Headings */ +h1, +h2, +h3, +h4, +h5, +h6 { + color: inherit; + font-weight: 500; + line-height: 1.2; + margin-bottom: 0.5em; + margin-top: 0; +} +.h1, +.h2, +.h3, +.h4, +.h5, +.h6 { + font-weight: 500; +} +h1, +.h1 { + font-size: 2rem; +} +h2, +.h2 { + font-size: 1.6rem; +} +h3, +.h3 { + font-size: 1.4rem; +} +h4, +.h4 { + font-size: 1.2rem; +} +h5, +.h5 { + font-size: 1rem; +} +h6, +.h6 { + font-size: 0.8rem; +} + +/* Paragraphs */ +p { + margin: 0 0 var(--line-height); +} + +/* Semantic text elements */ +a, +ins, +u { + text-decoration-skip-ink: auto; +} + +abbr[title] { + border-bottom: var(--border-width) dotted; + cursor: help; + text-decoration: none; +} + +/* Blockquote */ +blockquote { + border-left: var(--border-width-lg) solid var(--border-color); + margin-left: 0; + padding: var(--unit-2) var(--unit-4); + + & p:last-child { + margin-bottom: 0; + } +} + +/* Lists */ +ul, +ol { + margin: var(--unit-4) 0 var(--unit-4) var(--unit-4); + padding: 0; + + & ul, + & ol { + margin: var(--unit-4) 0 var(--unit-4) var(--unit-4); + } + + & li { + margin-top: var(--unit-2); + } +} + +ul { + list-style: disc inside; + + & ul { + list-style-type: circle; + } +} + +ol { + list-style: decimal inside; + + & ol { + list-style-type: lower-alpha; + } +} + +dl { + & dt { + font-weight: bold; + } + + & dd { + margin: var(--unit-1) 0 var(--unit-4) 0; + } +} diff --git a/bookmarks/styles/theme/utilities.css b/bookmarks/styles/theme/utilities.css new file mode 100644 index 0000000..74d4a79 --- /dev/null +++ b/bookmarks/styles/theme/utilities.css @@ -0,0 +1,296 @@ +/* Colors */ +.text-primary { + color: var(--primary-text-color); +} + +.text-secondary { + color: var(--secondary-text-color); +} + +.text-tertiary { + color: var(--tertiary-text-color); +} + +.text-success { + color: var(--success-color); +} + +.text-warning { + color: var(--warning-color); +} + +.text-error { + color: var(--error-color); +} + +.icon-color { + color: var(--icon-color); +} + +/* Display */ +.d-block { + display: block; +} + +.d-inline { + display: inline; +} + +.d-inline-block { + display: inline-block; +} + +.d-flex { + display: flex; +} + +.d-inline-flex { + display: inline-flex; +} + +.d-none, +.d-hide { + display: none !important; +} + +.d-visible { + visibility: visible; +} + +.d-invisible { + visibility: hidden; +} + +.text-hide { + background: transparent; + border: 0; + color: transparent; + font-size: 0; + line-height: 0; + text-shadow: none; +} + +.text-assistive { + border: 0; + clip: rect(0, 0, 0, 0); + height: 1px; + margin: -1px; + overflow: hidden; + padding: 0; + position: absolute; + width: 1px; +} + +/* Loading */ +.loading { + color: transparent !important; + min-height: var(--unit-4); + pointer-events: none; + position: relative; + + &::after { + animation: loading 500ms infinite linear; + background: transparent; + border: var(--border-width-lg) solid var(--primary-color); + border-radius: 50%; + border-right-color: transparent; + border-top-color: transparent; + content: ""; + display: block; + height: var(--unit-4); + left: 50%; + margin-left: calc(-1 * var(--unit-2)); + margin-top: calc(-1 * var(--unit-2)); + opacity: 1; + padding: 0; + position: absolute; + top: 50%; + width: var(--unit-4); + z-index: var(--zindex-0); + } + + &.loading-lg { + min-height: var(--unit-10); + + &::after { + height: var(--unit-8); + margin-left: calc(-1 * var(--unit-4)); + margin-top: calc(-1 * var(--unit-4)); + width: var(--unit-8); + } + } +} + +/* Position */ +.m-0 { + margin: 0 !important; +} + +.mb-0 { + margin-bottom: 0 !important; +} + +.ml-0 { + margin-left: 0 !important; +} + +.mr-0 { + margin-right: 0 !important; +} + +.mt-0 { + margin-top: 0 !important; +} + +.mx-0 { + margin-left: 0 !important; + margin-right: 0 !important; +} + +.my-0 { + margin-bottom: 0 !important; + margin-top: 0 !important; +} + +.m-1 { + margin: var(--unit-1) !important; +} + +.mb-1 { + margin-bottom: var(--unit-1) !important; +} + +.ml-1 { + margin-left: var(--unit-1) !important; +} + +.mr-1 { + margin-right: var(--unit-1) !important; +} + +.mt-1 { + margin-top: var(--unit-1) !important; +} + +.mx-1 { + margin-left: var(--unit-1) !important; + margin-right: var(--unit-1) !important; +} + +.my-1 { + margin-bottom: var(--unit-1) !important; + margin-top: var(--unit-1) !important; +} + +.m-2 { + margin: var(--unit-2) !important; +} + +.mb-2 { + margin-bottom: var(--unit-2) !important; +} + +.ml-2 { + margin-left: var(--unit-2) !important; +} + +.mr-2 { + margin-right: var(--unit-2) !important; +} + +.mt-2 { + margin-top: var(--unit-2) !important; +} + +.mx-2 { + margin-left: var(--unit-2) !important; + margin-right: var(--unit-2) !important; +} + +.my-2 { + margin-bottom: var(--unit-2) !important; + margin-top: var(--unit-2) !important; +} + +.m-4 { + margin: var(--unit-4) !important; +} + +.mb-4 { + margin-bottom: var(--unit-4) !important; +} + +.ml-4 { + margin-left: var(--unit-4) !important; +} + +.mr-4 { + margin-right: var(--unit-4) !important; +} + +.mt-4 { + margin-top: var(--unit-4) !important; +} + +.mx-4 { + margin-left: var(--unit-4) !important; + margin-right: var(--unit-4) !important; +} + +.my-4 { + margin-bottom: var(--unit-4) !important; + margin-top: var(--unit-4) !important; +} + +.mx-auto { + margin-left: auto; + margin-right: auto; +} + +/* Text */ +.text-normal { + font-weight: normal; +} + +.text-bold { + font-weight: bold; +} + +.text-italic { + font-style: italic; +} + +.text-large { + font-size: 1.2em; +} + +.text-small { + font-size: .9em; +} + +.text-tiny { + font-size: .8em; +} + +.text-muted { + opacity: .8; +} + +.truncate { + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} + +/* Flex */ +.align-baseline { + align-items: baseline; +} + +.align-center { + align-items: center; +} + +.justify-between { + justify-content: space-between; +} diff --git a/bookmarks/styles/theme/variables.css b/bookmarks/styles/theme/variables.css new file mode 100644 index 0000000..775f8e1 --- /dev/null +++ b/bookmarks/styles/theme/variables.css @@ -0,0 +1,135 @@ +:root { + /* Color palette */ + --gray-50: rgb(249, 250, 251); + --gray-100: rgb(243, 244, 246); + --gray-200: rgb(229, 231, 235); + --gray-300: rgb(209, 213, 219); + --gray-400: rgb(156, 163, 175); + --gray-500: rgb(107, 114, 128); + --gray-600: rgb(75, 85, 99); + --gray-700: rgb(55, 65, 81); + --gray-800: rgb(31, 41, 55); + --gray-900: rgb(17, 24, 39); + + --primary-color: hsl(241, 63%, 59%); + --primary-color-highlight: hsl(241, 63%, 64%); + --primary-color-shade: hsl(241, 63%, 59%, 0.075); + + --alternative-color: hsl(179, 94%, 29%); + --alternative-color-dark: hsl(179, 94%, 22%); + + --success-color: hsl(142, 76%, 36%); + --success-color-highlight: hsl(142, 76%, 40%); + --success-color-shade: hsla(142, 76%, 36%, 0.1); + + --warning-color: hsl(38, 92%, 50%); + --warning-color-highlight: hsl(38, 92%, 55%); + --warning-color-shade: hsla(38, 92%, 50%, 0.1); + + --error-color: hsl(0, 72%, 51%); + --error-color-highlight: hsl(0, 72%, 60%); + --error-color-shade: hsla(0, 72%, 51%, 0.1); + + /* Core colors */ + --text-color: var(--gray-700); + --secondary-text-color: var(--gray-500); + --tertiary-text-color: var(--gray-500); + --contrast-text-color: #fff; + --primary-text-color: hsl(241, 63%, 55%); + + --link-color: var(--primary-text-color); + --secondary-link-color: hsla(241, 63%, 54%, 0.8); + + --icon-color: var(--gray-500); + + --border-color: var(--gray-300); + --secondary-border-color: var(--gray-200); + + --body-color: #fff; + --body-color-contrast: var(--gray-100); + + /* Fonts */ + --base-font-family: -apple-system, system-ui, BlinkMacSystemFont, "Segoe UI", Roboto; + --mono-font-family: "SF Mono", "Segoe UI Mono", "Roboto Mono", Menlo, Courier, monospace; + --fallback-font-family: "Helvetica Neue", sans-serif; + --cjk-zh-hans-font-family: var(--base-font-family), "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", var(--fallback-font-family); + --cjk-zh-hant-font-family: var(--base-font-family), "PingFang TC", "Hiragino Sans CNS", "Microsoft JhengHei", var(--fallback-font-family); + --cjk-jp-font-family: var(--base-font-family), "Hiragino Sans", "Hiragino Kaku Gothic Pro", "Yu Gothic", YuGothic, Meiryo, var(--fallback-font-family); + --cjk-ko-font-family: var(--base-font-family), "Malgun Gothic", var(--fallback-font-family); + --body-font-family: var(--base-font-family), var(--fallback-font-family); + + /* Unit sizes */ + --unit-o: 0.05rem; + --unit-h: 0.1rem; + --unit-1: 0.2rem; + --unit-2: 0.4rem; + --unit-3: 0.6rem; + --unit-4: 0.8rem; + --unit-5: 1rem; + --unit-6: 1.2rem; + --unit-7: 1.4rem; + --unit-8: 1.6rem; + --unit-9: 1.8rem; + --unit-10: 2rem; + --unit-12: 2.4rem; + --unit-16: 3.2rem; + + /* Font sizes */ + --html-font-size: 20px; + --html-line-height: 1.5; + --font-size: 0.7rem; + --font-size-sm: 0.65rem; + --font-size-lg: 0.8rem; + --line-height: 1rem; + + /* Sizes */ + --layout-spacing: var(--unit-2); + --layout-spacing-sm: var(--unit-1); + --layout-spacing-lg: var(--unit-4); + --border-radius: var(--unit-1); + --border-radius-lg: var(--unit-2); + --border-width: var(--unit-o); + --border-width-lg: var(--unit-h); + --control-size: var(--unit-8); + --control-size-sm: var(--unit-6); + --control-size-lg: var(--unit-9); + --control-padding-x: var(--unit-2); + --control-padding-x-sm: calc(var(--unit-2) * 0.75); + --control-padding-x-lg: calc(var(--unit-2) * 1.5); + --control-padding-y: calc((var(--control-size) - var(--line-height)) / 2 - var(--border-width)); + --control-padding-y-sm: calc((var(--control-size-sm) - var(--line-height)) / 2 - var(--border-width)); + --control-padding-y-lg: calc((var(--control-size-lg) - var(--line-height)) / 2 - var(--border-width)); + --control-icon-size: 0.8rem; + + --control-width-xs: 180px; + --control-width-sm: 320px; + --control-width-md: 640px; + --control-width-lg: 960px; + --control-width-xl: 1280px; + + /* Responsive breakpoints */ + --size-xs: 480px; + --size-sm: 600px; + --size-md: 840px; + --size-lg: 960px; + --size-xl: 1280px; + --size-2x: 1440px; + + --responsive-breakpoint: var(--size-xs); + + /* Z-index */ + --zindex-0: 1; + --zindex-1: 100; + --zindex-2: 200; + --zindex-3: 300; + --zindex-4: 400; + + /* Focus */ + --focus-outline: 2px solid var(--primary-color); + --focus-outline-offset: 2px; + + /* Shadows */ + --box-shadow-xs: rgba(0, 0, 0, 0.05) 0px 1px 2px 0px; + --box-shadow: 0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1); + --box-shadow-lg: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1); +} diff --git a/bookmarks/styles/variables-dark.scss b/bookmarks/styles/variables-dark.scss deleted file mode 100644 index 17d0fed..0000000 --- a/bookmarks/styles/variables-dark.scss +++ /dev/null @@ -1,32 +0,0 @@ -$body-bg: #161822 !default; -$bg-color: lighten($body-bg, 5%) !default; -$bg-color-light: lighten($body-bg, 5%) !default; - -$border-color: #4C4E53 !default; -$border-color-dark: $border-color !default; - -$body-font-color: #b5bec8 !default; -$light-color: #fafafa !default; - -$gray-color: #7f879b !default; -$gray-color-dark: lighten($gray-color, 20%) !default; - -$primary-color: #a8b1ff !default; -$primary-color-dark: saturate($primary-color, 5%) !default; -$secondary-color: lighten($body-bg, 10%) !default; - -$link-color: $primary-color !default; -$link-color-dark: darken($link-color, 5%) !default; -$link-color-light: $link-color !default; - -$secondary-link-color: rgba(168, 177, 255, 0.73); - -$alternative-color: #59bdb9; -$alternative-color-dark: #73f1eb; - -$code-bg-color: rgba(255, 255, 255, 0.1); -$code-shadow-color: rgba(255, 255, 255, 0.2); - -/* Dark theme specific */ -$dt-primary-input-color: #5C68E7 !default; -$dt-primary-button-color: #5761cb !default; diff --git a/bookmarks/styles/variables-light.scss b/bookmarks/styles/variables-light.scss deleted file mode 100644 index c0b42cd..0000000 --- a/bookmarks/styles/variables-light.scss +++ /dev/null @@ -1,7 +0,0 @@ -$alternative-color: #05a6a3; -$alternative-color-dark: darken($alternative-color, 5%); - -$secondary-link-color: rgba(87, 85, 217, 0.64); - -$code-bg-color: rgba(0, 0, 0, 0.05); -$code-shadow-color: rgba(0, 0, 0, 0.15); diff --git a/bookmarks/templates/bookmarks/bookmark_list.html b/bookmarks/templates/bookmarks/bookmark_list.html index d413823..ae04219 100644 --- a/bookmarks/templates/bookmarks/bookmark_list.html +++ b/bookmarks/templates/bookmarks/bookmark_list.html @@ -58,18 +58,18 @@ {% endif %} {% endif %} {% if bookmark_item.notes %} -
+
{% markdown bookmark_item.notes %}
{% endif %} -
+
{% if bookmark_item.display_date %} {% if bookmark_item.web_archive_snapshot_url %} - {{ bookmark_item.display_date }} ∞ + {{ bookmark_item.display_date }} {% else %} {{ bookmark_item.display_date }} diff --git a/bookmarks/templates/bookmarks/bulk_edit/bar.html b/bookmarks/templates/bookmarks/bulk_edit/bar.html index 65837d7..847b998 100644 --- a/bookmarks/templates/bookmarks/bulk_edit/bar.html +++ b/bookmarks/templates/bookmarks/bulk_edit/bar.html @@ -1,7 +1,7 @@ {% load shared %} {% htmlmin %}
-
+
- +
- +
diff --git a/bookmarks/templates/settings/integrations.html b/bookmarks/templates/settings/integrations.html index 3ac1982..55bc836 100644 --- a/bookmarks/templates/settings/integrations.html +++ b/bookmarks/templates/settings/integrations.html @@ -35,10 +35,8 @@

REST API

The following token can be used to authenticate 3rd-party applications against the REST API:

-
-
- -
+
+

@@ -57,7 +55,7 @@

  • All bookmarks
  • Unread bookmarks
  • Shared bookmarks
  • -
  • Public shared bookmarks
    The public shared feed does not contain an authentication token and can be shared with other people. Only shows shared bookmarks from users who have explicitly enabled public sharing. +
  • Public shared bookmarks
    The public shared feed does not contain an authentication token and can be shared with other people. Only shows shared bookmarks from users who have explicitly enabled public sharing.
  • diff --git a/bookmarks/templates/settings/nav.html b/bookmarks/templates/settings/nav.html index 2956019..e111832 100644 --- a/bookmarks/templates/settings/nav.html +++ b/bookmarks/templates/settings/nav.html @@ -10,7 +10,7 @@ Integrations {% if request.user.is_superuser %} -

  • +
  • Admin diff --git a/bookmarks/tests/test_bookmark_new_view.py b/bookmarks/tests/test_bookmark_new_view.py index 7980bca..02c76ce 100644 --- a/bookmarks/tests/test_bookmark_new_view.py +++ b/bookmarks/tests/test_bookmark_new_view.py @@ -115,9 +115,6 @@ class BookmarkNewViewTestCase(TestCase, BookmarkFactoryMixin): -
    - Additional notes, supports Markdown. -
    """, html, diff --git a/bookmarks/tests/test_bookmarks_list_template.py b/bookmarks/tests/test_bookmarks_list_template.py index c6c4d75..86d1c7e 100644 --- a/bookmarks/tests/test_bookmarks_list_template.py +++ b/bookmarks/tests/test_bookmarks_list_template.py @@ -44,7 +44,7 @@ class BookmarkListTemplateTest(TestCase, BookmarkFactoryMixin, HtmlTestMixin): f"""
    - {label_content} ∞ + {label_content} | """, @@ -203,7 +203,7 @@ class BookmarkListTemplateTest(TestCase, BookmarkFactoryMixin, HtmlTestMixin): def assertNotes(self, html: str, notes_html: str, count=1): self.assertInHTML( f""" -
    +
    {notes_html}
    diff --git a/bookmarks/tests/test_nav_menu.py b/bookmarks/tests/test_nav_menu.py index b581325..e6ce5d6 100644 --- a/bookmarks/tests/test_nav_menu.py +++ b/bookmarks/tests/test_nav_menu.py @@ -18,7 +18,7 @@ class NavMenuTestCase(TestCase, BookmarkFactoryMixin): self.assertInHTML( f""" - Shared + Shared """, html, count=0, @@ -31,7 +31,7 @@ class NavMenuTestCase(TestCase, BookmarkFactoryMixin): self.assertInHTML( f""" - Shared + Shared """, html, count=2, diff --git a/bookmarks/views/partials/contexts.py b/bookmarks/views/partials/contexts.py index 6adcaea..701f597 100644 --- a/bookmarks/views/partials/contexts.py +++ b/bookmarks/views/partials/contexts.py @@ -383,13 +383,13 @@ class BookmarkAssetItem: icon_classes = [] text_classes = [] if asset.status == BookmarkAsset.STATUS_PENDING: - icon_classes.append("text-gray") - text_classes.append("text-gray") + icon_classes.append("text-tertiary") + text_classes.append("text-tertiary") elif asset.status == BookmarkAsset.STATUS_FAILURE: icon_classes.append("text-error") text_classes.append("text-error") else: - icon_classes.append("text-primary") + icon_classes.append("icon-color") self.icon_classes = " ".join(icon_classes) self.text_classes = " ".join(text_classes) diff --git a/docker/alpine.Dockerfile b/docker/alpine.Dockerfile index c782c7c..eeb214b 100644 --- a/docker/alpine.Dockerfile +++ b/docker/alpine.Dockerfile @@ -1,10 +1,11 @@ FROM node:18-alpine AS node-build WORKDIR /etc/linkding # install build dependencies -COPY rollup.config.mjs package.json package-lock.json ./ +COPY rollup.config.mjs postcss.config.js package.json package-lock.json ./ RUN npm ci # copy files needed for JS build COPY bookmarks/frontend ./bookmarks/frontend +COPY bookmarks/styles ./bookmarks/styles # run build RUN npm run build @@ -23,18 +24,15 @@ WORKDIR /etc/linkding FROM python-base AS python-build # install build dependencies COPY requirements.txt requirements.txt -COPY requirements.dev.txt requirements.dev.txt -# remove playwright from requirements as there is not always a distro and it's not needed for the build -RUN sed -i '/playwright/d' requirements.dev.txt -RUN pip install -U pip && pip install -r requirements.txt -r requirements.dev.txt +RUN pip install -U pip && pip install -r requirements.txt # copy files needed for Django build COPY . . COPY --from=node-build /etc/linkding . +# remove style sources +RUN rm -rf bookmarks/styles # run Django part of the build RUN mkdir data && \ - python manage.py compilescss && \ - python manage.py collectstatic --ignore=*.scss && \ - python manage.py compilescss --delete-files + python manage.py collectstatic FROM python-base AS prod-deps diff --git a/docker/default.Dockerfile b/docker/default.Dockerfile index cacdb3b..409febc 100644 --- a/docker/default.Dockerfile +++ b/docker/default.Dockerfile @@ -1,10 +1,11 @@ FROM node:18-alpine AS node-build WORKDIR /etc/linkding # install build dependencies -COPY rollup.config.mjs package.json package-lock.json ./ +COPY rollup.config.mjs postcss.config.js package.json package-lock.json ./ RUN npm ci # copy files needed for JS build COPY bookmarks/frontend ./bookmarks/frontend +COPY bookmarks/styles ./bookmarks/styles # run build RUN npm run build @@ -25,18 +26,15 @@ WORKDIR /etc/linkding FROM python-base AS python-build # install build dependencies COPY requirements.txt requirements.txt -COPY requirements.dev.txt requirements.dev.txt -# remove playwright from requirements as there is not always a distro and it's not needed for the build -RUN sed -i '/playwright/d' requirements.dev.txt -RUN pip install -U pip && pip install -r requirements.txt -r requirements.dev.txt +RUN pip install -U pip && pip install -r requirements.txt # copy files needed for Django build COPY . . COPY --from=node-build /etc/linkding . +# remove style sources +RUN rm -rf bookmarks/styles # run Django part of the build RUN mkdir data && \ - python manage.py compilescss && \ - python manage.py collectstatic --ignore=*.scss && \ - python manage.py compilescss --delete-files + python manage.py collectstatic FROM python-base AS prod-deps diff --git a/docs/header.afdesign b/docs/header.afdesign index b3de360..cd74168 100644 Binary files a/docs/header.afdesign and b/docs/header.afdesign differ diff --git a/docs/header.png b/docs/header.png index 6e2c97e..c4efc4e 100644 Binary files a/docs/header.png and b/docs/header.png differ diff --git a/docs/header.svg b/docs/header.svg index 91a9dc1..b2eb321 100644 --- a/docs/header.svg +++ b/docs/header.svg @@ -4,12 +4,12 @@ - + - + - + diff --git a/docs/linkding-screenshot.png b/docs/linkding-screenshot.png index 005f8ce..99cd028 100644 Binary files a/docs/linkding-screenshot.png and b/docs/linkding-screenshot.png differ diff --git a/package-lock.json b/package-lock.json index 899a253..0037f36 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,17 +1,22 @@ { "name": "linkding", - "version": "1.30.0", + "version": "1.31.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "linkding", - "version": "1.30.0", + "version": "1.31.1", "license": "MIT", "dependencies": { "@rollup/plugin-node-resolve": "^15.2.3", "@rollup/plugin-terser": "^0.4.4", "@rollup/wasm-node": "^4.13.0", + "cssnano": "^7.0.6", + "postcss": "^8.4.45", + "postcss-cli": "^11.0.0", + "postcss-import": "^16.1.0", + "postcss-nesting": "^13.0.0", "rollup-plugin-svelte": "^7.2.0", "spectre.css": "^0.5.8", "svelte": "^4.0.0" @@ -32,6 +37,48 @@ "node": ">=6.0.0" } }, + "node_modules/@csstools/selector-resolve-nested": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@csstools/selector-resolve-nested/-/selector-resolve-nested-2.0.0.tgz", + "integrity": "sha512-oklSrRvOxNeeOW1yARd4WNCs/D09cQjunGZUgSq6vM8GpzFswN+8rBZyJA29YFZhOTQ6GFzxgLDNtVbt9wPZMA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss-selector-parser": "^6.1.0" + } + }, + "node_modules/@csstools/selector-specificity": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@csstools/selector-specificity/-/selector-specificity-4.0.0.tgz", + "integrity": "sha512-189nelqtPd8++phaHNwYovKZI0FOzH1vQEE3QhHHkNIGrg5fSs9CbYP3RvfEH5geztnIA9Jwq91wyOIwAW5JIQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss-selector-parser": "^6.1.0" + } + }, "node_modules/@jridgewell/gen-mapping": { "version": "0.3.5", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", @@ -84,6 +131,38 @@ "@jridgewell/sourcemap-codec": "^1.4.14" } }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, "node_modules/@rollup/plugin-node-resolve": { "version": "15.2.3", "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-15.2.3.tgz", @@ -337,6 +416,25 @@ "fsevents": "~2.3.2" } }, + "node_modules/@sindresorhus/merge-streams": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/merge-streams/-/merge-streams-2.3.0.tgz", + "integrity": "sha512-LtoMMhxAlorcGhmFYI+LhPgbPZCkgP6ra1YL604EeF6U98pLlQ3iWIGMdWSC+vWmPBWBNgmDBAhnAobLROJmwg==", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@trysound/sax": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@trysound/sax/-/sax-0.2.0.tgz", + "integrity": "sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==", + "engines": { + "node": ">=10.13.0" + } + }, "node_modules/@types/estree": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", @@ -358,6 +456,40 @@ "node": ">=0.4.0" } }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, "node_modules/aria-query": { "version": "5.3.0", "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.0.tgz", @@ -374,6 +506,64 @@ "dequal": "^2.0.3" } }, + "node_modules/binary-extensions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==" + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browserslist": { + "version": "4.23.3", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.3.tgz", + "integrity": "sha512-btwCFJVjI4YWDNfau8RhZ+B1Q/VLoUITrm3RlP6y1tYGWIOa+InuYiRGXUBXo8nA1qKmHMyLB/iVQg5TT4eFoA==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "caniuse-lite": "^1.0.30001646", + "electron-to-chromium": "^1.5.4", + "node-releases": "^2.0.18", + "update-browserslist-db": "^1.1.0" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, "node_modules/buffer-from": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", @@ -390,6 +580,72 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/caniuse-api": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/caniuse-api/-/caniuse-api-3.0.0.tgz", + "integrity": "sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw==", + "dependencies": { + "browserslist": "^4.0.0", + "caniuse-lite": "^1.0.0", + "lodash.memoize": "^4.1.2", + "lodash.uniq": "^4.5.0" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001660", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001660.tgz", + "integrity": "sha512-GacvNTTuATm26qC74pt+ad1fW15mlQ/zuTzzY1ZoIzECTP8HURDfF43kNxPgf7H1jmelCBQTTbBNxdSXOA7Bqg==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ] + }, + "node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, "node_modules/code-red": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/code-red/-/code-red-1.0.4.tgz", @@ -410,11 +666,58 @@ "@types/estree": "^1.0.0" } }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/colord": { + "version": "2.9.3", + "resolved": "https://registry.npmjs.org/colord/-/colord-2.9.3.tgz", + "integrity": "sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw==" + }, "node_modules/commander": { "version": "2.20.3", "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" }, + "node_modules/css-declaration-sorter": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/css-declaration-sorter/-/css-declaration-sorter-7.2.0.tgz", + "integrity": "sha512-h70rUM+3PNFuaBDTLe8wF/cdWu+dOZmb7pJt8Z2sedYbAcQVQV/tEchueg3GWxwqS0cxtbxmaHEdkNACqcvsow==", + "engines": { + "node": "^14 || ^16 || >=18" + }, + "peerDependencies": { + "postcss": "^8.0.9" + } + }, + "node_modules/css-select": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.1.0.tgz", + "integrity": "sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==", + "dependencies": { + "boolbase": "^1.0.0", + "css-what": "^6.1.0", + "domhandler": "^5.0.2", + "domutils": "^3.0.1", + "nth-check": "^2.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, "node_modules/css-tree": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.3.1.tgz", @@ -427,6 +730,131 @@ "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0" } }, + "node_modules/css-what": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz", + "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==", + "engines": { + "node": ">= 6" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "bin": { + "cssesc": "bin/cssesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/cssnano": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cssnano/-/cssnano-7.0.6.tgz", + "integrity": "sha512-54woqx8SCbp8HwvNZYn68ZFAepuouZW4lTwiMVnBErM3VkO7/Sd4oTOt3Zz3bPx3kxQ36aISppyXj2Md4lg8bw==", + "dependencies": { + "cssnano-preset-default": "^7.0.6", + "lilconfig": "^3.1.2" + }, + "engines": { + "node": "^18.12.0 || ^20.9.0 || >=22.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/cssnano" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/cssnano-preset-default": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cssnano-preset-default/-/cssnano-preset-default-7.0.6.tgz", + "integrity": "sha512-ZzrgYupYxEvdGGuqL+JKOY70s7+saoNlHSCK/OGn1vB2pQK8KSET8jvenzItcY+kA7NoWvfbb/YhlzuzNKjOhQ==", + "dependencies": { + "browserslist": "^4.23.3", + "css-declaration-sorter": "^7.2.0", + "cssnano-utils": "^5.0.0", + "postcss-calc": "^10.0.2", + "postcss-colormin": "^7.0.2", + "postcss-convert-values": "^7.0.4", + "postcss-discard-comments": "^7.0.3", + "postcss-discard-duplicates": "^7.0.1", + "postcss-discard-empty": "^7.0.0", + "postcss-discard-overridden": "^7.0.0", + "postcss-merge-longhand": "^7.0.4", + "postcss-merge-rules": "^7.0.4", + "postcss-minify-font-values": "^7.0.0", + "postcss-minify-gradients": "^7.0.0", + "postcss-minify-params": "^7.0.2", + "postcss-minify-selectors": "^7.0.4", + "postcss-normalize-charset": "^7.0.0", + "postcss-normalize-display-values": "^7.0.0", + "postcss-normalize-positions": "^7.0.0", + "postcss-normalize-repeat-style": "^7.0.0", + "postcss-normalize-string": "^7.0.0", + "postcss-normalize-timing-functions": "^7.0.0", + "postcss-normalize-unicode": "^7.0.2", + "postcss-normalize-url": "^7.0.0", + "postcss-normalize-whitespace": "^7.0.0", + "postcss-ordered-values": "^7.0.1", + "postcss-reduce-initial": "^7.0.2", + "postcss-reduce-transforms": "^7.0.0", + "postcss-svgo": "^7.0.1", + "postcss-unique-selectors": "^7.0.3" + }, + "engines": { + "node": "^18.12.0 || ^20.9.0 || >=22.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/cssnano-utils": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cssnano-utils/-/cssnano-utils-5.0.0.tgz", + "integrity": "sha512-Uij0Xdxc24L6SirFr25MlwC2rCFX6scyUmuKpzI+JQ7cyqDEwD42fJ0xfB3yLfOnRDU5LKGgjQ9FA6LYh76GWQ==", + "engines": { + "node": "^18.12.0 || ^20.9.0 || >=22.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/csso": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/csso/-/csso-5.0.5.tgz", + "integrity": "sha512-0LrrStPOdJj+SPCCrGhzryycLjwcgUSHBtxNA8aIDxf0GLsRh1cKYhB00Gd1lDOS4yGH69+SNn13+TWbVHETFQ==", + "dependencies": { + "css-tree": "~2.2.0" + }, + "engines": { + "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0", + "npm": ">=7.0.0" + } + }, + "node_modules/csso/node_modules/css-tree": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.2.1.tgz", + "integrity": "sha512-OA0mILzGc1kCOCSJerOeqDxDQ4HOh+G8NbOJFOTgOCzpw7fCBubk0fEyxp8AgOL/jvLgYA/uV0cMbe43ElF1JA==", + "dependencies": { + "mdn-data": "2.0.28", + "source-map-js": "^1.0.1" + }, + "engines": { + "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0", + "npm": ">=7.0.0" + } + }, + "node_modules/csso/node_modules/mdn-data": { + "version": "2.0.28", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.28.tgz", + "integrity": "sha512-aylIc7Z9y4yzHYAJNuESG3hfhC+0Ibp/MAMiaOZgNv4pmEdFyfZhhhny4MNiAfWdBQ1RQ2mfDWmM1x8SvGyp8g==" + }, "node_modules/deepmerge": { "version": "4.3.1", "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", @@ -435,6 +863,14 @@ "node": ">=0.10.0" } }, + "node_modules/dependency-graph": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/dependency-graph/-/dependency-graph-0.11.0.tgz", + "integrity": "sha512-JeMq7fEshyepOWDfcfHK06N3MhyPhz++vtqWhMT5O9A3K42rdsEDpfdVqjaqaAhsw6a+ZqeDvQVtD0hFHQWrzg==", + "engines": { + "node": ">= 0.6.0" + } + }, "node_modules/dequal": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", @@ -443,11 +879,138 @@ "node": ">=6" } }, + "node_modules/dom-serializer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", + "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", + "dependencies": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.2", + "entities": "^4.2.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + } + }, + "node_modules/domelementtype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ] + }, + "node_modules/domhandler": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", + "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", + "dependencies": { + "domelementtype": "^2.3.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/domutils": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.1.0.tgz", + "integrity": "sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==", + "dependencies": { + "dom-serializer": "^2.0.0", + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, + "node_modules/electron-to-chromium": { + "version": "1.5.20", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.20.tgz", + "integrity": "sha512-74mdl6Fs1HHzK9SUX4CKFxAtAe3nUns48y79TskHNAG6fGOlLfyKA4j855x+0b5u8rWJIrlaG9tcTPstMlwjIw==" + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + }, + "node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "engines": { + "node": ">=6" + } + }, "node_modules/estree-walker": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==" }, + "node_modules/fast-glob": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", + "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fastq": { + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", + "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/fs-extra": { + "version": "11.2.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.2.0.tgz", + "integrity": "sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=14.14" + } + }, "node_modules/fsevents": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", @@ -469,6 +1032,60 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-stdin": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-9.0.0.tgz", + "integrity": "sha512-dVKBjfWisLAicarI2Sf+JuBE/DghV4UzNAVe9yhEJuzeREd3JhOTE9cUaJTeSa77fsbQUK3pcOpJfM59+VKZaA==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/globby": { + "version": "14.0.2", + "resolved": "https://registry.npmjs.org/globby/-/globby-14.0.2.tgz", + "integrity": "sha512-s3Fq41ZVh7vbbe2PN3nrW7yC7U7MFVc5c98/iTl9c2GawNMKx/J648KQRW6WKkuU8GIbbh2IXfIRQjOZnXcTnw==", + "dependencies": { + "@sindresorhus/merge-streams": "^2.1.0", + "fast-glob": "^3.3.2", + "ignore": "^5.2.4", + "path-type": "^5.0.0", + "slash": "^5.1.0", + "unicorn-magic": "^0.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==" + }, "node_modules/hasown": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", @@ -480,6 +1097,25 @@ "node": ">= 0.4" } }, + "node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "engines": { + "node": ">= 4" + } + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/is-builtin-module": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-3.2.1.tgz", @@ -505,11 +1141,46 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/is-module": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz", "integrity": "sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==" }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "engines": { + "node": ">=0.12.0" + } + }, "node_modules/is-reference": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-3.0.2.tgz", @@ -518,11 +1189,43 @@ "@types/estree": "*" } }, + "node_modules/jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/lilconfig": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.2.tgz", + "integrity": "sha512-eop+wDAvpItUys0FWkHIKeC9ybYrTGbU41U5K7+bttZZeohvnY7M9dZ5kB21GNWiFT2q1OoPTvncPCgSOVO5ow==", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antonk52" + } + }, "node_modules/locate-character": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/locate-character/-/locate-character-3.0.0.tgz", "integrity": "sha512-SW13ws7BjaeJ6p7Q6CO2nchbYEc3X3J6WrmTTDto7yMPqVSZTUyY5Tjbid+Ab8gLnATtygYtiDIJGQRRn2ZOiA==" }, + "node_modules/lodash.memoize": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", + "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==" + }, + "node_modules/lodash.uniq": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", + "integrity": "sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==" + }, "node_modules/magic-string": { "version": "0.30.8", "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.8.tgz", @@ -539,11 +1242,83 @@ "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.30.tgz", "integrity": "sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==" }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/nanoid": { + "version": "3.3.7", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", + "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/node-releases": { + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.18.tgz", + "integrity": "sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==" + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/nth-check": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", + "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", + "dependencies": { + "boolbase": "^1.0.0" + }, + "funding": { + "url": "https://github.com/fb55/nth-check?sponsor=1" + } + }, "node_modules/path-parse": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" }, + "node_modules/path-type": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-5.0.0.tgz", + "integrity": "sha512-5HviZNaZcfqP95rwpv+1HDgUamezbqdSYTyzjTvwtJSnIH+3vnbmWsItli8OFEndS984VT55M3jduxZbX351gg==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/periscopic": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/periscopic/-/periscopic-3.1.0.tgz", @@ -562,6 +1337,11 @@ "@types/estree": "^1.0.0" } }, + "node_modules/picocolors": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.0.tgz", + "integrity": "sha512-TQ92mBOW0l3LeMeyLV6mzy/kWr8lkd/hp3mTg7wYK7zJhuBStmGMBG0BdeDZS/dZx1IukaX6Bk11zcln25o1Aw==" + }, "node_modules/picomatch": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", @@ -573,6 +1353,575 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, + "node_modules/pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postcss": { + "version": "8.4.45", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.45.tgz", + "integrity": "sha512-7KTLTdzdZZYscUc65XmjFiB73vBhBfbPztCYdUNvlaso9PrzjzcmjqBPR0lNGkcVlcO4BjiO5rK/qNz+XAen1Q==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "nanoid": "^3.3.7", + "picocolors": "^1.0.1", + "source-map-js": "^1.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/postcss-calc": { + "version": "10.0.2", + "resolved": "https://registry.npmjs.org/postcss-calc/-/postcss-calc-10.0.2.tgz", + "integrity": "sha512-DT/Wwm6fCKgpYVI7ZEWuPJ4az8hiEHtCUeYjZXqU7Ou4QqYh1Df2yCQ7Ca6N7xqKPFkxN3fhf+u9KSoOCJNAjg==", + "dependencies": { + "postcss-selector-parser": "^6.1.2", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^18.12 || ^20.9 || >=22.0" + }, + "peerDependencies": { + "postcss": "^8.4.38" + } + }, + "node_modules/postcss-cli": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/postcss-cli/-/postcss-cli-11.0.0.tgz", + "integrity": "sha512-xMITAI7M0u1yolVcXJ9XTZiO9aO49mcoKQy6pCDFdMh9kGqhzLVpWxeD/32M/QBmkhcGypZFFOLNLmIW4Pg4RA==", + "dependencies": { + "chokidar": "^3.3.0", + "dependency-graph": "^0.11.0", + "fs-extra": "^11.0.0", + "get-stdin": "^9.0.0", + "globby": "^14.0.0", + "picocolors": "^1.0.0", + "postcss-load-config": "^5.0.0", + "postcss-reporter": "^7.0.0", + "pretty-hrtime": "^1.0.3", + "read-cache": "^1.0.0", + "slash": "^5.0.0", + "yargs": "^17.0.0" + }, + "bin": { + "postcss": "index.js" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.0.0" + } + }, + "node_modules/postcss-colormin": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/postcss-colormin/-/postcss-colormin-7.0.2.tgz", + "integrity": "sha512-YntRXNngcvEvDbEjTdRWGU606eZvB5prmHG4BF0yLmVpamXbpsRJzevyy6MZVyuecgzI2AWAlvFi8DAeCqwpvA==", + "dependencies": { + "browserslist": "^4.23.3", + "caniuse-api": "^3.0.0", + "colord": "^2.9.3", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^18.12.0 || ^20.9.0 || >=22.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-convert-values": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/postcss-convert-values/-/postcss-convert-values-7.0.4.tgz", + "integrity": "sha512-e2LSXPqEHVW6aoGbjV9RsSSNDO3A0rZLCBxN24zvxF25WknMPpX8Dm9UxxThyEbaytzggRuZxaGXqaOhxQ514Q==", + "dependencies": { + "browserslist": "^4.23.3", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^18.12.0 || ^20.9.0 || >=22.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-discard-comments": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/postcss-discard-comments/-/postcss-discard-comments-7.0.3.tgz", + "integrity": "sha512-q6fjd4WU4afNhWOA2WltHgCbkRhZPgQe7cXF74fuVB/ge4QbM9HEaOIzGSiMvM+g/cOsNAUGdf2JDzqA2F8iLA==", + "dependencies": { + "postcss-selector-parser": "^6.1.2" + }, + "engines": { + "node": "^18.12.0 || ^20.9.0 || >=22.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-discard-duplicates": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/postcss-discard-duplicates/-/postcss-discard-duplicates-7.0.1.tgz", + "integrity": "sha512-oZA+v8Jkpu1ct/xbbrntHRsfLGuzoP+cpt0nJe5ED2FQF8n8bJtn7Bo28jSmBYwqgqnqkuSXJfSUEE7if4nClQ==", + "engines": { + "node": "^18.12.0 || ^20.9.0 || >=22.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-discard-empty": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/postcss-discard-empty/-/postcss-discard-empty-7.0.0.tgz", + "integrity": "sha512-e+QzoReTZ8IAwhnSdp/++7gBZ/F+nBq9y6PomfwORfP7q9nBpK5AMP64kOt0bA+lShBFbBDcgpJ3X4etHg4lzA==", + "engines": { + "node": "^18.12.0 || ^20.9.0 || >=22.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-discard-overridden": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/postcss-discard-overridden/-/postcss-discard-overridden-7.0.0.tgz", + "integrity": "sha512-GmNAzx88u3k2+sBTZrJSDauR0ccpE24omTQCVmaTTZFz1du6AasspjaUPMJ2ud4RslZpoFKyf+6MSPETLojc6w==", + "engines": { + "node": "^18.12.0 || ^20.9.0 || >=22.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-import": { + "version": "16.1.0", + "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-16.1.0.tgz", + "integrity": "sha512-7hsAZ4xGXl4MW+OKEWCnF6T5jqBw80/EE9aXg1r2yyn1RsVEU8EtKXbijEODa+rg7iih4bKf7vlvTGYR4CnPNg==", + "dependencies": { + "postcss-value-parser": "^4.0.0", + "read-cache": "^1.0.0", + "resolve": "^1.1.7" + }, + "engines": { + "node": ">=18.0.0" + }, + "peerDependencies": { + "postcss": "^8.0.0" + } + }, + "node_modules/postcss-load-config": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-5.1.0.tgz", + "integrity": "sha512-G5AJ+IX0aD0dygOE0yFZQ/huFFMSNneyfp0e3/bT05a8OfPC5FUoZRPfGijUdGOJNMewJiwzcHJXFafFzeKFVA==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "lilconfig": "^3.1.1", + "yaml": "^2.4.2" + }, + "engines": { + "node": ">= 18" + }, + "peerDependencies": { + "jiti": ">=1.21.0", + "postcss": ">=8.0.9", + "tsx": "^4.8.1" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + }, + "postcss": { + "optional": true + }, + "tsx": { + "optional": true + } + } + }, + "node_modules/postcss-merge-longhand": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/postcss-merge-longhand/-/postcss-merge-longhand-7.0.4.tgz", + "integrity": "sha512-zer1KoZA54Q8RVHKOY5vMke0cCdNxMP3KBfDerjH/BYHh4nCIh+1Yy0t1pAEQF18ac/4z3OFclO+ZVH8azjR4A==", + "dependencies": { + "postcss-value-parser": "^4.2.0", + "stylehacks": "^7.0.4" + }, + "engines": { + "node": "^18.12.0 || ^20.9.0 || >=22.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-merge-rules": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/postcss-merge-rules/-/postcss-merge-rules-7.0.4.tgz", + "integrity": "sha512-ZsaamiMVu7uBYsIdGtKJ64PkcQt6Pcpep/uO90EpLS3dxJi6OXamIobTYcImyXGoW0Wpugh7DSD3XzxZS9JCPg==", + "dependencies": { + "browserslist": "^4.23.3", + "caniuse-api": "^3.0.0", + "cssnano-utils": "^5.0.0", + "postcss-selector-parser": "^6.1.2" + }, + "engines": { + "node": "^18.12.0 || ^20.9.0 || >=22.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-minify-font-values": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/postcss-minify-font-values/-/postcss-minify-font-values-7.0.0.tgz", + "integrity": "sha512-2ckkZtgT0zG8SMc5aoNwtm5234eUx1GGFJKf2b1bSp8UflqaeFzR50lid4PfqVI9NtGqJ2J4Y7fwvnP/u1cQog==", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^18.12.0 || ^20.9.0 || >=22.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-minify-gradients": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/postcss-minify-gradients/-/postcss-minify-gradients-7.0.0.tgz", + "integrity": "sha512-pdUIIdj/C93ryCHew0UgBnL2DtUS3hfFa5XtERrs4x+hmpMYGhbzo6l/Ir5de41O0GaKVpK1ZbDNXSY6GkXvtg==", + "dependencies": { + "colord": "^2.9.3", + "cssnano-utils": "^5.0.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^18.12.0 || ^20.9.0 || >=22.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-minify-params": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/postcss-minify-params/-/postcss-minify-params-7.0.2.tgz", + "integrity": "sha512-nyqVLu4MFl9df32zTsdcLqCFfE/z2+f8GE1KHPxWOAmegSo6lpV2GNy5XQvrzwbLmiU7d+fYay4cwto1oNdAaQ==", + "dependencies": { + "browserslist": "^4.23.3", + "cssnano-utils": "^5.0.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^18.12.0 || ^20.9.0 || >=22.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-minify-selectors": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/postcss-minify-selectors/-/postcss-minify-selectors-7.0.4.tgz", + "integrity": "sha512-JG55VADcNb4xFCf75hXkzc1rNeURhlo7ugf6JjiiKRfMsKlDzN9CXHZDyiG6x/zGchpjQS+UAgb1d4nqXqOpmA==", + "dependencies": { + "cssesc": "^3.0.0", + "postcss-selector-parser": "^6.1.2" + }, + "engines": { + "node": "^18.12.0 || ^20.9.0 || >=22.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-nesting": { + "version": "13.0.0", + "resolved": "https://registry.npmjs.org/postcss-nesting/-/postcss-nesting-13.0.0.tgz", + "integrity": "sha512-TCGQOizyqvEkdeTPM+t6NYwJ3EJszYE/8t8ILxw/YoeUvz2rz7aM8XTAmBWh9/DJjfaaabL88fWrsVHSPF2zgA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "dependencies": { + "@csstools/selector-resolve-nested": "^2.0.0", + "@csstools/selector-specificity": "^4.0.0", + "postcss-selector-parser": "^6.1.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-normalize-charset": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/postcss-normalize-charset/-/postcss-normalize-charset-7.0.0.tgz", + "integrity": "sha512-ABisNUXMeZeDNzCQxPxBCkXexvBrUHV+p7/BXOY+ulxkcjUZO0cp8ekGBwvIh2LbCwnWbyMPNJVtBSdyhM2zYQ==", + "engines": { + "node": "^18.12.0 || ^20.9.0 || >=22.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-normalize-display-values": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/postcss-normalize-display-values/-/postcss-normalize-display-values-7.0.0.tgz", + "integrity": "sha512-lnFZzNPeDf5uGMPYgGOw7v0BfB45+irSRz9gHQStdkkhiM0gTfvWkWB5BMxpn0OqgOQuZG/mRlZyJxp0EImr2Q==", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^18.12.0 || ^20.9.0 || >=22.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-normalize-positions": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/postcss-normalize-positions/-/postcss-normalize-positions-7.0.0.tgz", + "integrity": "sha512-I0yt8wX529UKIGs2y/9Ybs2CelSvItfmvg/DBIjTnoUSrPxSV7Z0yZ8ShSVtKNaV/wAY+m7bgtyVQLhB00A1NQ==", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^18.12.0 || ^20.9.0 || >=22.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-normalize-repeat-style": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/postcss-normalize-repeat-style/-/postcss-normalize-repeat-style-7.0.0.tgz", + "integrity": "sha512-o3uSGYH+2q30ieM3ppu9GTjSXIzOrRdCUn8UOMGNw7Af61bmurHTWI87hRybrP6xDHvOe5WlAj3XzN6vEO8jLw==", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^18.12.0 || ^20.9.0 || >=22.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-normalize-string": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/postcss-normalize-string/-/postcss-normalize-string-7.0.0.tgz", + "integrity": "sha512-w/qzL212DFVOpMy3UGyxrND+Kb0fvCiBBujiaONIihq7VvtC7bswjWgKQU/w4VcRyDD8gpfqUiBQ4DUOwEJ6Qg==", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^18.12.0 || ^20.9.0 || >=22.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-normalize-timing-functions": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/postcss-normalize-timing-functions/-/postcss-normalize-timing-functions-7.0.0.tgz", + "integrity": "sha512-tNgw3YV0LYoRwg43N3lTe3AEWZ66W7Dh7lVEpJbHoKOuHc1sLrzMLMFjP8SNULHaykzsonUEDbKedv8C+7ej6g==", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^18.12.0 || ^20.9.0 || >=22.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-normalize-unicode": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/postcss-normalize-unicode/-/postcss-normalize-unicode-7.0.2.tgz", + "integrity": "sha512-ztisabK5C/+ZWBdYC+Y9JCkp3M9qBv/XFvDtSw0d/XwfT3UaKeW/YTm/MD/QrPNxuecia46vkfEhewjwcYFjkg==", + "dependencies": { + "browserslist": "^4.23.3", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^18.12.0 || ^20.9.0 || >=22.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-normalize-url": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/postcss-normalize-url/-/postcss-normalize-url-7.0.0.tgz", + "integrity": "sha512-+d7+PpE+jyPX1hDQZYG+NaFD+Nd2ris6r8fPTBAjE8z/U41n/bib3vze8x7rKs5H1uEw5ppe9IojewouHk0klQ==", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^18.12.0 || ^20.9.0 || >=22.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-normalize-whitespace": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/postcss-normalize-whitespace/-/postcss-normalize-whitespace-7.0.0.tgz", + "integrity": "sha512-37/toN4wwZErqohedXYqWgvcHUGlT8O/m2jVkAfAe9Bd4MzRqlBmXrJRePH0e9Wgnz2X7KymTgTOaaFizQe3AQ==", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^18.12.0 || ^20.9.0 || >=22.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-ordered-values": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/postcss-ordered-values/-/postcss-ordered-values-7.0.1.tgz", + "integrity": "sha512-irWScWRL6nRzYmBOXReIKch75RRhNS86UPUAxXdmW/l0FcAsg0lvAXQCby/1lymxn/o0gVa6Rv/0f03eJOwHxw==", + "dependencies": { + "cssnano-utils": "^5.0.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^18.12.0 || ^20.9.0 || >=22.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-reduce-initial": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/postcss-reduce-initial/-/postcss-reduce-initial-7.0.2.tgz", + "integrity": "sha512-pOnu9zqQww7dEKf62Nuju6JgsW2V0KRNBHxeKohU+JkHd/GAH5uvoObqFLqkeB2n20mr6yrlWDvo5UBU5GnkfA==", + "dependencies": { + "browserslist": "^4.23.3", + "caniuse-api": "^3.0.0" + }, + "engines": { + "node": "^18.12.0 || ^20.9.0 || >=22.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-reduce-transforms": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/postcss-reduce-transforms/-/postcss-reduce-transforms-7.0.0.tgz", + "integrity": "sha512-pnt1HKKZ07/idH8cpATX/ujMbtOGhUfE+m8gbqwJE05aTaNw8gbo34a2e3if0xc0dlu75sUOiqvwCGY3fzOHew==", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^18.12.0 || ^20.9.0 || >=22.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-reporter": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/postcss-reporter/-/postcss-reporter-7.1.0.tgz", + "integrity": "sha512-/eoEylGWyy6/DOiMP5lmFRdmDKThqgn7D6hP2dXKJI/0rJSO1ADFNngZfDzxL0YAxFvws+Rtpuji1YIHj4mySA==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "picocolors": "^1.0.0", + "thenby": "^1.3.4" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-selector-parser": { + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz", + "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-svgo": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/postcss-svgo/-/postcss-svgo-7.0.1.tgz", + "integrity": "sha512-0WBUlSL4lhD9rA5k1e5D8EN5wCEyZD6HJk0jIvRxl+FDVOMlJ7DePHYWGGVc5QRqrJ3/06FTXM0bxjmJpmTPSA==", + "dependencies": { + "postcss-value-parser": "^4.2.0", + "svgo": "^3.3.2" + }, + "engines": { + "node": "^18.12.0 || ^20.9.0 || >= 18" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-unique-selectors": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/postcss-unique-selectors/-/postcss-unique-selectors-7.0.3.tgz", + "integrity": "sha512-J+58u5Ic5T1QjP/LDV9g3Cx4CNOgB5vz+kM6+OxHHhFACdcDeKhBXjQmB7fnIZM12YSTvsL0Opwco83DmacW2g==", + "dependencies": { + "postcss-selector-parser": "^6.1.2" + }, + "engines": { + "node": "^18.12.0 || ^20.9.0 || >=22.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-value-parser": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==" + }, "node_modules/prettier": { "version": "3.2.5", "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.2.5.tgz", @@ -588,6 +1937,33 @@ "url": "https://github.com/prettier/prettier?sponsor=1" } }, + "node_modules/pretty-hrtime": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz", + "integrity": "sha512-66hKPCr+72mlfiSjlEB1+45IjXSqvVAIy6mocupoww4tBFE9R9IhwwUGoI4G++Tc9Aq+2rxOt0RFU6gPcrte0A==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, "node_modules/randombytes": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", @@ -596,6 +1972,33 @@ "safe-buffer": "^5.1.0" } }, + "node_modules/read-cache": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", + "integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==", + "dependencies": { + "pify": "^2.3.0" + } + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/resolve": { "version": "1.22.8", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", @@ -620,6 +2023,15 @@ "node": ">=10" } }, + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, "node_modules/rollup": { "version": "4.13.0", "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.13.0.tgz", @@ -680,6 +2092,28 @@ "node": ">= 8.0.0" } }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, "node_modules/safe-buffer": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", @@ -707,6 +2141,17 @@ "randombytes": "^2.1.0" } }, + "node_modules/slash": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-5.1.0.tgz", + "integrity": "sha512-ZA6oR3T/pEyuqwMgAKT0/hAv8oAXckzbkmR0UkUosQ+Mc4RxGoJkRmwHgHufaenlyAgE1Mxgpdcrf75y6XcnDg==", + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/smob": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/smob/-/smob-1.4.1.tgz", @@ -721,9 +2166,9 @@ } }, "node_modules/source-map-js": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", - "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", "engines": { "node": ">=0.10.0" } @@ -742,6 +2187,45 @@ "resolved": "https://registry.npmjs.org/spectre.css/-/spectre.css-0.5.9.tgz", "integrity": "sha512-9jUqwZmCnvflrxFGcK+ize43TvjwDjqMwZPVubEtSIHzvinH0TBUESm1LcOJx3Ur7bdPaeOHQIjOqBl1Y5kLFw==" }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/stylehacks": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/stylehacks/-/stylehacks-7.0.4.tgz", + "integrity": "sha512-i4zfNrGMt9SB4xRK9L83rlsFCgdGANfeDAYacO1pkqcE7cRHPdWHwnKZVz7WY17Veq/FvyYsRAU++Ga+qDFIww==", + "dependencies": { + "browserslist": "^4.23.3", + "postcss-selector-parser": "^6.1.2" + }, + "engines": { + "node": "^18.12.0 || ^20.9.0 || >=22.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, "node_modules/supports-preserve-symlinks-flag": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", @@ -785,6 +2269,38 @@ "@types/estree": "^1.0.0" } }, + "node_modules/svgo": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/svgo/-/svgo-3.3.2.tgz", + "integrity": "sha512-OoohrmuUlBs8B8o6MB2Aevn+pRIH9zDALSR+6hhqVfa6fRwG/Qw9VUMSMW9VNg2CFc/MTIfabtdOVl9ODIJjpw==", + "dependencies": { + "@trysound/sax": "0.2.0", + "commander": "^7.2.0", + "css-select": "^5.1.0", + "css-tree": "^2.3.1", + "css-what": "^6.1.0", + "csso": "^5.0.5", + "picocolors": "^1.0.0" + }, + "bin": { + "svgo": "bin/svgo" + }, + "engines": { + "node": ">=14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/svgo" + } + }, + "node_modules/svgo/node_modules/commander": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", + "engines": { + "node": ">= 10" + } + }, "node_modules/terser": { "version": "5.29.2", "resolved": "https://registry.npmjs.org/terser/-/terser-5.29.2.tgz", @@ -801,6 +2317,135 @@ "engines": { "node": ">=10" } + }, + "node_modules/thenby": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/thenby/-/thenby-1.3.4.tgz", + "integrity": "sha512-89Gi5raiWA3QZ4b2ePcEwswC3me9JIg+ToSgtE0JWeCynLnLxNr/f9G+xfo9K+Oj4AFdom8YNJjibIARTJmapQ==" + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/unicorn-magic": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.1.0.tgz", + "integrity": "sha512-lRfVq8fE8gz6QMBuDM6a+LO3IAzTi05H6gCVaUpir2E1Rwpo4ZUog45KpNXKC/Mn3Yb9UDuHumeFTo9iV/D9FQ==", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.0.tgz", + "integrity": "sha512-EdRAaAyk2cUE1wOf2DkEhzxqOQvFOoRJFNS6NeyJ01Gp2beMRpBAINjM2iDXE3KCuKhwnvHIQCJm6ThL2Z+HzQ==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "escalade": "^3.1.2", + "picocolors": "^1.0.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "engines": { + "node": ">=10" + } + }, + "node_modules/yaml": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.5.1.tgz", + "integrity": "sha512-bLQOjaX/ADgQ20isPJRvF0iRUHIxVhYvr53Of7wGcWlO2jvtUlH5m87DsmulFVxRpNLOnI4tB6p/oh8D7kpn9Q==", + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "engines": { + "node": ">=12" + } } } } diff --git a/package.json b/package.json index 4772fa0..883f1bf 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,10 @@ "description": "", "main": "index.js", "scripts": { - "build": "rollup -c", + "build": "npm run build-js && npm run build-theme-light && npm run build-theme-dark", + "build-js": "rollup -c", + "build-theme-light": "postcss -o bookmarks/static/theme-light.css bookmarks/styles/theme-light.css", + "build-theme-dark": "postcss -o bookmarks/static/theme-dark.css bookmarks/styles/theme-dark.css", "dev": "rollup -c -w" }, "repository": { @@ -22,6 +25,11 @@ "@rollup/plugin-node-resolve": "^15.2.3", "@rollup/plugin-terser": "^0.4.4", "@rollup/wasm-node": "^4.13.0", + "cssnano": "^7.0.6", + "postcss": "^8.4.45", + "postcss-cli": "^11.0.0", + "postcss-import": "^16.1.0", + "postcss-nesting": "^13.0.0", "rollup-plugin-svelte": "^7.2.0", "spectre.css": "^0.5.8", "svelte": "^4.0.0" diff --git a/postcss.config.js b/postcss.config.js new file mode 100644 index 0000000..9eb08c9 --- /dev/null +++ b/postcss.config.js @@ -0,0 +1,13 @@ +const cssnano = require("cssnano"); +const postcssImport = require("postcss-import"); +const postcssNesting = require("postcss-nesting"); + +module.exports = { + plugins: [ + postcssImport, + postcssNesting, + cssnano({ + preset: "default", + }), + ], +}; diff --git a/requirements.dev.in b/requirements.dev.in index 09776d8..fc2af78 100644 --- a/requirements.dev.in +++ b/requirements.dev.in @@ -1,8 +1,6 @@ black coverage -django-compressor django-debug-toolbar -libsass playwright pytest pytest-django diff --git a/requirements.dev.txt b/requirements.dev.txt index 2ff8a9c..0a3c137 100644 --- a/requirements.dev.txt +++ b/requirements.dev.txt @@ -13,13 +13,7 @@ click==8.1.7 coverage==7.4.1 # via -r requirements.dev.in django==5.0.8 - # via - # django-appconf - # django-debug-toolbar -django-appconf==1.0.6 - # via django-compressor -django-compressor==4.4 - # via -r requirements.dev.in + # via django-debug-toolbar django-debug-toolbar==4.2.0 # via -r requirements.dev.in execnet==2.1.1 @@ -28,8 +22,6 @@ greenlet==3.0.3 # via playwright iniconfig==2.0.0 # via pytest -libsass==0.23.0 - # via -r requirements.dev.in mypy-extensions==1.0.0 # via black packaging==23.2 @@ -55,10 +47,6 @@ pytest-django==4.7.0 # via -r requirements.dev.in pytest-xdist==3.6.1 # via -r requirements.dev.in -rcssmin==1.1.1 - # via django-compressor -rjsmin==1.2.1 - # via django-compressor sqlparse==0.5.0 # via # django diff --git a/requirements.in b/requirements.in index 20ac8b3..99c8fdf 100644 --- a/requirements.in +++ b/requirements.in @@ -3,7 +3,6 @@ bleach bleach-allowlist Django django-registration -django-sass-processor django-widget-tweaks djangorestframework huey diff --git a/requirements.txt b/requirements.txt index 43aa13f..cdb8e7a 100644 --- a/requirements.txt +++ b/requirements.txt @@ -35,8 +35,6 @@ django==5.0.8 # mozilla-django-oidc django-registration==3.4 # via -r requirements.in -django-sass-processor==1.4 - # via -r requirements.in django-widget-tweaks==1.5.0 # via -r requirements.in djangorestframework==3.15.2 diff --git a/scripts/test-e2e.sh b/scripts/test-e2e.sh index 76f4385..80ad485 100755 --- a/scripts/test-e2e.sh +++ b/scripts/test-e2e.sh @@ -6,9 +6,7 @@ playwright install chromium # Test server loads assets from static folder, so make sure files there are up-to-date rm -rf static npm run build -python manage.py compilescss -python manage.py collectstatic --ignore=*.scss -python manage.py compilescss --delete-files +python manage.py collectstatic # Run E2E tests python manage.py test bookmarks.e2e --pattern="e2e_test_*.py" diff --git a/siteroot/settings/base.py b/siteroot/settings/base.py index acede34..12d0447 100644 --- a/siteroot/settings/base.py +++ b/siteroot/settings/base.py @@ -39,7 +39,6 @@ INSTALLED_APPS = [ "django.contrib.sessions", "django.contrib.messages", "django.contrib.staticfiles", - "sass_processor", "widget_tweaks", "rest_framework", "rest_framework.authtoken", @@ -129,19 +128,10 @@ STATIC_URL = "/" + LD_CONTEXT_PATH + "static/" # Collect static files in static folder STATIC_ROOT = os.path.join(BASE_DIR, "static") -# Turn off SASS compilation by default -SASS_PROCESSOR_ENABLED = False - -# Add SASS preprocessor finder to resolve generated CSS -STATICFILES_FINDERS = [ - "django.contrib.staticfiles.finders.FileSystemFinder", - "django.contrib.staticfiles.finders.AppDirectoriesFinder", - "sass_processor.finders.CssFinder", -] - -# Enable SASS processor to find custom folder for SCSS sources through static file finders STATICFILES_DIRS = [ + # Resolve theme files from style source folder os.path.join(BASE_DIR, "bookmarks", "styles"), + # Resolve downloaded files in dev environment os.path.join(BASE_DIR, "data", "favicons"), os.path.join(BASE_DIR, "data", "previews"), ] diff --git a/siteroot/settings/dev.py b/siteroot/settings/dev.py index 277fd5e..1c3341f 100644 --- a/siteroot/settings/dev.py +++ b/siteroot/settings/dev.py @@ -8,8 +8,6 @@ from .base import * # Turn on debug mode DEBUG = True -# Turn on SASS compilation -SASS_PROCESSOR_ENABLED = True # Enable debug toolbar INSTALLED_APPS.append("debug_toolbar") diff --git a/siteroot/settings/prod.py b/siteroot/settings/prod.py index 8ce17fc..48f36e9 100644 --- a/siteroot/settings/prod.py +++ b/siteroot/settings/prod.py @@ -11,8 +11,6 @@ from .base import * # Turn of debug mode DEBUG = False -# Turn off SASS compilation -SASS_PROCESSOR_ENABLED = False # Try read secret key from file try: