-
-
Save m1r1c1/0c463f7731e5c1c88a8b24d69a1b448a to your computer and use it in GitHub Desktop.
Custom CSS to give linkding a dark, card-based layout
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /* | |
| Card-based layout for Linkding | |
| Large images, fully clickable | |
| Entire card selectable in bulk edit mode | |
| Tags moved to expandable sidebar | |
| 01/11/2026 - MRC - Modified using Claude AI | |
| to have CSS applied to Linkding 1.45. Also | |
| modified to use same card style layout but | |
| a little differently that meets my needs a | |
| little better. | |
| 07/18/2026 - MRC - Modified using Claude AI | |
| Fable to standardize and improve organization | |
| of CSS. Should be no major functional change. | |
| Author: Brett Terpstra (https://brettterpstra.com) | |
| GitHub: @ttscoff <https://github.com/ttscoff> | |
| Modified for updated Linkding version | |
| License: MIT | |
| Refactor notes: | |
| - All colors are defined once in :root as RGB channel triplets, so both | |
| solid colors and rgba() variants derive from a single source. | |
| To re-theme the skin, edit only the "PALETTE" block below. | |
| - Layout magic numbers are derived from a few anchor values (image height, | |
| card padding, actions height). Formulas are noted where they were | |
| inferred from the original hand-tuned values. | |
| */ | |
| :root { | |
| /* ========================================================== | |
| PALETTE — edit these triplets to re-theme the entire skin | |
| ========================================================== */ | |
| --bg-rgb: 0, 18, 25; /* page background (#001219) */ | |
| --mint-rgb: 148, 210, 189; /* light accent / links (#94d2bd) */ | |
| --teal-rgb: 10, 147, 150; /* mid accent / hovers (#0a9396) */ | |
| --deep-rgb: 0, 95, 115; /* buttons / tag pills (#005f73) */ | |
| --orange-rgb: 202, 103, 2; /* "redux" label (#ca6702) */ | |
| --cyan-bright-rgb: 15, 217, 222;/* link hover (#0fd9de) */ | |
| --danger-rgb: 220, 41, 23; /* delete / destructive (#dc2917) */ | |
| --danger-bright-rgb: 255, 42, 21; /* confirm-cancel "×" (#ff2a15) */ | |
| --tooltip-rgb: 0, 91, 127; /* title tooltip bg (#005b7f) */ | |
| --khaki-rgb: 153, 136, 87; /* action btn-link border */ | |
| --neutral-border-rgb: 51, 51, 51; /* card borders, notes (#333) */ | |
| --neutral-text-rgb: 170, 170, 170; /* description text (#aaa) */ | |
| /* Solid colors derived from the triplets */ | |
| --color-bg: rgb(var(--bg-rgb)); | |
| --color-mint: rgb(var(--mint-rgb)); | |
| --color-teal: rgb(var(--teal-rgb)); | |
| --color-deep: rgb(var(--deep-rgb)); | |
| --color-orange: rgb(var(--orange-rgb)); | |
| --color-cyan-bright: rgb(var(--cyan-bright-rgb)); | |
| --color-danger: rgb(var(--danger-rgb)); | |
| --color-danger-bright: rgb(var(--danger-bright-rgb)); | |
| --color-tooltip: rgb(var(--tooltip-rgb)); | |
| --color-border: rgb(var(--neutral-border-rgb)); | |
| --color-desc-text: rgb(var(--neutral-text-rgb)); | |
| /* ========================================================== | |
| LAYOUT ANCHORS — dependent values derive from these | |
| ========================================================== */ | |
| --card-image-height: 200px; /* preview image height (the master value) */ | |
| --card-padding: 10px; /* inner card padding */ | |
| --card-border-width: 1px; /* card border */ | |
| --card-radius: 8px; | |
| --actions-height: 70px; /* bottom action bar height */ | |
| --sidebar-width: 250px; | |
| --header-clearance: 100px; /* sticky offset below the fixed header */ | |
| /* Derived layout values */ | |
| /* Top padding = image height + card padding (was 210px) */ | |
| --card-top-padding: calc(var(--card-image-height) + var(--card-padding)); | |
| /* Clickable image overlay = image height + 50px overlap (was 250px) */ | |
| --card-overlay-height: calc(var(--card-image-height) + 50px); | |
| /* Bulk-edit checkbox: generous cover, 3x image height (was 600px) */ | |
| --bulk-checkbox-height: calc(var(--card-image-height) * 3); | |
| /* Checkbox offsets: padding + border(s) (were -11px / -212px) */ | |
| --bulk-checkbox-left: calc(-1 * (var(--card-padding) + var(--card-border-width))); | |
| --bulk-checkbox-top: calc(-1 * (var(--card-top-padding) + 2 * var(--card-border-width))); | |
| /* Description overlay (expand-on-hover) */ | |
| --desc-top-offset: 3em; /* sits just below the title */ | |
| --desc-collapsed-height: 4.3em; | |
| --desc-expanded-height: 15em; | |
| /* URL clearance keeps the url line above the actions bar (was 7.3em) */ | |
| --url-bottom-clearance: 7.3em; | |
| /* Notes tab (collapsed) */ | |
| --notes-tab-width: 44px; | |
| --notes-tab-height: 23px; | |
| --notes-tab-bottom: 34px; | |
| /* ========================================================== | |
| Linkding theme variables mapped onto the palette | |
| ========================================================== */ | |
| --primary-color: var(--color-mint); | |
| --primary-text-color: #fff; | |
| --btn-primary-bg-color: var(--color-deep); | |
| --btn-primary-hover-bg-color: var(--color-teal); | |
| --btn-primary-text-color: #fff; | |
| --btn-link-text-color: var(--color-mint); | |
| --btn-link-hover-text-color: var(--color-cyan-bright); | |
| --checkbox-checked-bg-color: var(--color-deep); | |
| --checkbox-bg-color: rgba(var(--deep-rgb), 0.75); | |
| --tab-active-color: var(--color-mint); | |
| --tab-highlight-color: var(--color-teal); | |
| --tab-hover-color: var(--color-teal); | |
| --focus-outline: var(--color-mint); | |
| --input-border-color: #1e493a; | |
| --btn-border-color: #1e493a; | |
| } | |
| body { | |
| --fbc-blue-60: var(--color-bg); | |
| --fbc-blue-70: var(--color-bg); | |
| background: var(--color-bg); | |
| margin-top: 0px; | |
| } | |
| /* Logo */ | |
| a { | |
| color: var(--color-mint); | |
| } | |
| .btn { | |
| color: var(--color-mint); | |
| } | |
| .btn .btn-primary { | |
| background: var(--color-deep); | |
| color: var(--color-mint); | |
| } | |
| .btn .btn-primary:hover { | |
| color: var(--color-teal); | |
| } | |
| header h1 { | |
| transform: rotate(-5deg) translate(-7px, -13px); | |
| } | |
| header h1::after { | |
| color: var(--color-orange); | |
| content: " redux"; | |
| left: 0; | |
| opacity: 0.8; | |
| position: absolute; | |
| top: 1em; | |
| } | |
| /* Make header sticky */ | |
| header { | |
| position: sticky; | |
| top: 0; | |
| z-index: 100; | |
| background: var(--color-bg); | |
| padding-top: 20px; | |
| padding-bottom: 20px; | |
| margin-bottom: 0px; | |
| } | |
| /* Tag cloud styling */ | |
| .tag-cloud .unselected-tags a { | |
| border-radius: 15px; | |
| border: solid 1px rgba(var(--deep-rgb), 0.3); | |
| color: var(--color-deep); | |
| display: inline-block; | |
| font-weight: 500; | |
| margin: 0 0 0.25em 0 !important; | |
| padding: 0 6px; | |
| transition: all 0.3s ease-in-out; | |
| } | |
| .tag-cloud .highlight-char { | |
| color: var(--color-teal); | |
| } | |
| .tag-cloud .unselected-tags a:hover, | |
| .tag-cloud .unselected-tags a:focus, | |
| .tag-cloud .unselected-tags a:visited:hover, | |
| .tag-cloud .unselected-tags a:visited:focus { | |
| background: rgba(var(--mint-rgb), 0.8); | |
| box-shadow: 0 0 4px rgba(var(--mint-rgb), 0.35); | |
| text-decoration: none; | |
| transform: scale(1.1); | |
| transition: all 0.15s ease-in-out; | |
| } | |
| .tag-cloud a { | |
| font-weight: 500; | |
| } | |
| /* Bookmark cards */ | |
| ul.bookmark-list>li { | |
| background-color: rgba(var(--deep-rgb), 0.09); | |
| border-radius: var(--card-radius); | |
| border: solid var(--card-border-width) var(--color-border); | |
| display: block; | |
| gap: 0px 0px; | |
| margin: 0 10px 10px 0; | |
| min-width: 250px; | |
| overflow: hidden; | |
| padding: var(--card-top-padding) var(--card-padding) var(--card-padding) var(--card-padding); | |
| position: relative; | |
| width: 100%; | |
| } | |
| ul.bookmark-list>li .title img + a::before { | |
| content: ""; | |
| display: block; | |
| height: var(--card-overlay-height); | |
| left: calc(-1 * var(--card-padding)); | |
| position: absolute; | |
| top: calc(-1 * var(--card-overlay-height)); | |
| width: 110%; | |
| z-index: 8; | |
| } | |
| ul.bookmark-list>li .preview-image { | |
| height: var(--card-image-height); | |
| left: 0; | |
| position: absolute; | |
| top: 0; | |
| width: 100%; | |
| } | |
| ul.bookmark-list>li .title img { | |
| top: var(--card-padding); | |
| transition: transform 0.2s ease-in-out; | |
| } | |
| ul.bookmark-list>li .title:hover img { | |
| transform: translateY(-50%) scale(1.3); | |
| transition: transform 0.2s ease-in-out; | |
| } | |
| ul.bookmark-list>li .title a[data-tooltip]:focus::after, | |
| ul.bookmark-list>li .title a[data-tooltip]:hover::after { | |
| background: var(--color-tooltip); | |
| border-color: var(--color-deep); | |
| } | |
| @media screen and (min-width: 770px) { | |
| ul.bookmark-list>li { | |
| width: 48%; | |
| } | |
| } | |
| @media screen and (min-width: 900px) { | |
| ul.bookmark-list>li { | |
| width: 32%; | |
| } | |
| } | |
| @media screen and (min-width: 1300px) { | |
| ul.bookmark-list>li { | |
| width: 24%; | |
| } | |
| } | |
| /* Make image clickable */ | |
| ul.bookmark-list { | |
| display: flex; | |
| flex-direction: row; | |
| flex-wrap: wrap; | |
| } | |
| ul.bookmark-list>li .title { | |
| background: 0; | |
| } | |
| ul.bookmark-list>li .content { | |
| display: block; | |
| height: 100%; | |
| max-width: 100%; | |
| padding-bottom: var(--actions-height); | |
| position: relative; | |
| width: 100%; | |
| } | |
| ul.bookmark-list>li .title a { | |
| width: 100%; | |
| color: #fff; | |
| } | |
| ul.bookmark-list>li .url-display, | |
| ul.bookmark-list>li .url-path { | |
| margin-bottom: var(--url-bottom-clearance); | |
| color: var(--color-mint); | |
| } | |
| /* Re-enable grid for bookmarks page to show sidebar */ | |
| .bookmarks-page.grid { | |
| display: grid !important; | |
| grid-template-columns: 1fr var(--sidebar-width) !important; | |
| gap: 20px; | |
| max-width: 100%; | |
| } | |
| /* Force main content to take first column */ | |
| .bookmarks-page.grid > main.col-2 { | |
| grid-column: 1 !important; | |
| min-width: 0; /* Prevent grid overflow */ | |
| height: calc(100vh - var(--header-clearance) - 50px); | |
| overflow-y: auto; | |
| } | |
| /* Force sidebar to take second column */ | |
| .bookmarks-page.grid > div.side-panel.col-1 { | |
| grid-column: 2 !important; | |
| display: block !important; | |
| visibility: visible !important; | |
| opacity: 1 !important; | |
| background: rgba(var(--bg-rgb), 0.95); | |
| border-radius: var(--card-radius); | |
| border: solid 2px rgba(var(--teal-rgb), 0.85); | |
| padding: 20px; | |
| position: sticky; | |
| top: var(--header-clearance); | |
| max-height: calc(100vh - var(--header-clearance) - 20px); | |
| overflow-y: auto; | |
| width: var(--sidebar-width) !important; | |
| min-width: var(--sidebar-width) !important; | |
| } | |
| /* Make section-header sticky within main */ | |
| .section-header { | |
| position: sticky; | |
| top: 0; | |
| z-index: 10; | |
| background: var(--color-bg); | |
| } | |
| /* Section headers in sidebar */ | |
| .bookmarks-page.grid div.side-panel h2, | |
| .bookmarks-page.grid div.side-panel h3, | |
| .bookmarks-page.grid .col-1 h2, | |
| .bookmarks-page.grid .col-1 h3 { | |
| color: var(--color-teal); | |
| font-size: var(--font-size-lg); | |
| margin-bottom: var(--unit-4); | |
| margin-top: 0; | |
| } | |
| .bookmarks-page.grid div.side-panel section, | |
| .bookmarks-page.grid .col-1 section { | |
| margin-bottom: var(--unit-8); | |
| } | |
| .bookmarks-page.grid div.side-panel section:last-child, | |
| .bookmarks-page.grid .col-1 section:last-child { | |
| margin-bottom: 0; | |
| } | |
| /* Bundle menu styling */ | |
| .bundle-menu { | |
| list-style-type: none; | |
| margin: 0 0 var(--unit-6); | |
| padding: 0; | |
| } | |
| .bundle-menu .bundle-menu-item { | |
| margin: 0; | |
| margin-bottom: var(--unit-2); | |
| } | |
| .bundle-menu .bundle-menu-item a { | |
| border-radius: 15px; | |
| padding: var(--unit-1) var(--unit-2); | |
| color: var(--color-deep); | |
| border: solid 1px rgba(var(--deep-rgb), 0.3); | |
| display: block; | |
| text-decoration: none; | |
| transition: all 0.2s ease-in-out; | |
| font-weight: 500; | |
| } | |
| .bundle-menu .bundle-menu-item a:hover, | |
| .bundle-menu .bundle-menu-item a:focus { | |
| background: rgba(var(--mint-rgb), 0.8); | |
| box-shadow: 0 0 4px rgba(var(--mint-rgb), 0.35); | |
| text-decoration: none; | |
| transform: scale(1.05); | |
| } | |
| .bundle-menu .bundle-menu-item.selected a { | |
| background: var(--color-deep); | |
| color: var(--color-mint); | |
| border-color: var(--color-deep); | |
| } | |
| /* Other grid elements stay as block */ | |
| .grid:not(.bookmarks-page) { | |
| display: block; | |
| } | |
| .container { | |
| max-width: 100%; | |
| } | |
| /* Make entire card clickable in bulk edit mode */ | |
| ld-bookmark-page.active ul.bookmark-list>li .form-checkbox.bulk-edit-checkbox { | |
| cursor: pointer; | |
| height: var(--bulk-checkbox-height); | |
| left: var(--bulk-checkbox-left); | |
| top: var(--bulk-checkbox-top); | |
| transform: none; | |
| width: 109%; | |
| z-index: 10; | |
| } | |
| a[data-turbo-frame="details-modal"] { | |
| clear: left; | |
| } | |
| /* Card tags */ | |
| ul.bookmark-list>li .tags { | |
| margin: 1em 0; | |
| } | |
| ul.bookmark-list>li .tags a:link, | |
| ul.bookmark-list>li .tags a:visited, | |
| ul.bookmark-list>li .tags a:hover, | |
| ul.bookmark-list>li .tags a:focus { | |
| background: var(--color-deep); | |
| border-radius: 15px; | |
| color: var(--color-mint); | |
| font-size: 90%; | |
| padding: 3px 6px; | |
| text-decoration: none; | |
| transition: all 0.1s linear; | |
| } | |
| /* Preview image */ | |
| ul.bookmark-list>li .preview-image, | |
| ul.bookmark-list>li .preview-image.placeholder { | |
| border: 0; | |
| border-radius: 0; | |
| margin-top: 0; | |
| background: linear-gradient(0deg, var(--color-mint) 0%, var(--color-deep) 100%); | |
| } | |
| ul.bookmark-list>li .preview-image.placeholder .img { | |
| mask: 0; | |
| background-color: transparent; | |
| } | |
| /* Description */ | |
| ul.bookmark-list>li .description { | |
| color: var(--color-desc-text); | |
| margin: 1em 0; | |
| } | |
| ul.bookmark-list>li .description.separate { | |
| -webkit-mask-image: linear-gradient(180deg, #000 60%, transparent); | |
| max-height: var(--desc-collapsed-height); | |
| position: absolute; | |
| top: var(--desc-top-offset); | |
| background: rgba(var(--bg-rgb), 0.7); | |
| padding: 5px; | |
| transition: all 0.2s linear; | |
| white-space: wrap; | |
| } | |
| ul.bookmark-list>li .description.separate:hover { | |
| -webkit-mask-image: linear-gradient(180deg, #000 60%, #000); | |
| max-height: var(--desc-expanded-height); | |
| transition: all 0.3s ease-in-out; | |
| z-index: 11; | |
| } | |
| /* Actions */ | |
| ul.bookmark-list>li .actions, | |
| ul.bookmark-list>li .extra-actions { | |
| bottom: 0; | |
| display: block; | |
| left: 0; | |
| position: absolute; | |
| } | |
| ul.bookmark-list>li .actions { | |
| bottom: 0; | |
| height: var(--actions-height); | |
| margin-top: 10px; | |
| padding-top: 10px; | |
| position: absolute; | |
| width: 100%; | |
| } | |
| ul.bookmark-list>li .actions a { | |
| padding: 0 4px; | |
| } | |
| ul.bookmark-list>li .actions button.btn-link { | |
| padding: 0 4px; | |
| border: solid 1px rgba(var(--khaki-rgb), 0.5); | |
| } | |
| .extra-actions { | |
| clear: both; | |
| display: block; | |
| padding-top: 5px; | |
| width: 100%; | |
| } | |
| .actions span { | |
| display: none; | |
| } | |
| .extra-actions .btn { | |
| background: rgba(var(--teal-rgb), 0.5); | |
| } | |
| ul.bookmark-list>li .actions a { | |
| background-color: var(--color-deep); | |
| border-radius: 4px; | |
| color: var(--color-mint); | |
| float: left; | |
| margin: 0 4px 4px 0; | |
| padding: 0 4px; | |
| text-align: center; | |
| width: 50px; | |
| } | |
| ul.bookmark-list>li .actions a:first-of-type { | |
| background: 0; | |
| border: 0; | |
| bottom: 0; | |
| color: var(--color-deep); | |
| margin: 0; | |
| padding: 0 4px 0 0; | |
| position: absolute; | |
| right: 0; | |
| width: auto; | |
| z-index: 10; | |
| } | |
| ul.bookmark-list>li .actions a:hover { | |
| background: var(--color-mint); | |
| color: var(--color-deep) !important; | |
| transition: all 0.1s linear; | |
| } | |
| ul.bookmark-list>li .actions button.btn-link { | |
| background: rgba(var(--danger-rgb), 0.25); | |
| border: solid 1px rgba(var(--danger-rgb), 0.5); | |
| color: var(--color-danger); | |
| opacity: 0.6; | |
| } | |
| ul.bookmark-list>li .actions button.btn-link:hover { | |
| opacity: 1; | |
| transition: all 0.1s linear; | |
| } | |
| ul.bookmark-list>li .actions a:first-of-type:hover { | |
| background-color: transparent; | |
| color: var(--color-mint) !important; | |
| transition: color 0.1s linear; | |
| } | |
| ul.bookmark-list>li .actions .extra-actions button.btn-link { | |
| background: 0; | |
| border: 0; | |
| color: var(--color-mint); | |
| opacity: 0.5; | |
| padding: 0; | |
| } | |
| ul.bookmark-list>li .actions .extra-actions button.btn-link:hover, | |
| ul.bookmark-list>li .actions .extra-actions button.btn-link:focus { | |
| opacity: 1; | |
| } | |
| ul.bookmark-list>li .actions a { | |
| float: left; | |
| } | |
| .actions span.confirmation { | |
| margin-right: 4px; | |
| display: block; | |
| float: left; | |
| } | |
| .actions span.confirmation .btn { | |
| margin: 0 4px; | |
| margin: 0; | |
| position: relative; | |
| visibility: hidden; | |
| width: 22px; | |
| } | |
| .actions span.confirmation .btn::before { | |
| border-radius: 4px; | |
| border: solid 1px; | |
| color: var(--color-mint); | |
| content: "\2713"; | |
| display: inline-block; | |
| font-size: 150%; | |
| font-weight: 600; | |
| height: 20px; | |
| left: 0; | |
| padding: 0; | |
| position: absolute; | |
| top: 0; | |
| visibility: visible; | |
| width: 20px; | |
| z-index: 1; | |
| } | |
| .actions span.confirmation .btn.mr-1::before { | |
| color: var(--color-danger-bright); | |
| content: "\00D7"; | |
| font-size: 180%; | |
| line-height: 0.65; | |
| } | |
| ul.bookmark-list>li .actions button.btn-link { | |
| float: left; | |
| margin-right: 4px; | |
| } | |
| /* pagination */ | |
| .bookmark-pagination.sticky { | |
| background: var(--color-bg); | |
| border: 0px; | |
| margin: 0px; | |
| padding: 0px; | |
| position: absolute; | |
| padding-bottom: 25px; | |
| } | |
| .bookmark-pagination.sticky::before { | |
| background: var(--color-bg); | |
| } | |
| /* notes */ | |
| ul.bookmark-list .notes { | |
| background: var(--color-border); | |
| bottom: var(--notes-tab-bottom); | |
| display: block; | |
| height: var(--notes-tab-height); | |
| max-height: 100%; | |
| overflow: hidden; | |
| position: absolute; | |
| right: 0; | |
| width: var(--notes-tab-width); | |
| z-index: 1000; | |
| } | |
| ul.bookmark-list .notes::before { | |
| background: var(--color-border); | |
| border-radius: 4px; | |
| color: #888; | |
| content: "Note"; | |
| cursor: pointer; | |
| display: block; | |
| padding: 0 6px; | |
| position: absolute; | |
| right: 0; | |
| top: 1px; | |
| } | |
| ul.bookmark-list .notes:hover { | |
| width: 100%; | |
| height: auto; | |
| } | |
| ul.bookmark-list .notes:hover::before { | |
| display: none; | |
| } | |
| .header-controls { | |
| margin-right: 15px; | |
| } | |
| /* Reduce card height when preview images are disabled/missing */ | |
| ul.bookmark-list>li:not(:has(.preview-image)) { | |
| padding: var(--card-padding) !important; | |
| } | |
| /* Adjust title positioning when no preview image */ | |
| ul.bookmark-list>li:not(:has(.preview-image)) .title img + a::before { | |
| display: none; | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment