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 %} -