├── LICENSE ├── README.md ├── roam-live-preview.user.js ├── roam-mappletons-andy-subdued.css ├── roam-sidebar-modifier.css ├── roam-sticky-sidebar.css └── time-format.user.js /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Palash Karia 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # roam-modifiers 2 | [userscripts](#tampermonkey-scripts)/custom CSS files for Roam Research 3 | 4 | ## Styles 5 | 6 | The mappletons-andy theme (thanks to [@mapplestons](https://twitter.com/Mappletons) and [@vandermerwed](https://twitter.com/vandermerwed) :) 7 | 8 | I have some more modifications applied on top of it. 9 | 10 | 11 | - Sidebar overlay/slide in - don't move content on hover 🔥 12 | - this is pretty hacky, but I am going to keep this updated if it breaks. I need it too much. 13 | 14 | - Viewdata square (⌗) for block refs 🚀 15 | - Seems appropriate, as # evolved from ⌗ :) 16 | 17 | - Better scrollbars 🤓 18 | - (increase size on hover, have space around them (like OSX!)) 19 | - This uses a tiny border CSS hack I learned, using border to create the space 20 | 21 | - Other modifications are mostly color/width changes :) 22 | 23 | See images below 24 | 25 | Sidebar overlay (no content push) | Block ref (⌗) 26 | :-------------------------:|:-------------------------: 27 | ![image](https://user-images.githubusercontent.com/2976363/83698596-74ae5300-a61f-11ea-9c2a-1078aaa6070e.png) | ![image](https://user-images.githubusercontent.com/2976363/83698671-ae7f5980-a61f-11ea-93b1-fdc2e66312f8.png) 28 | 29 | 30 | I use [stylus](https://chrome.google.com/webstore/detail/stylus/clngdbkpkpeebahjckkjfobafhncgmne?hl=en) for applying these 31 | 32 | 33 | ## Tampermonkey scripts 34 | Click on the raw github link to trigger a tampermonkey download. 35 | 36 | ### /Current Time format to AM/PM 37 | #### time-format.js 38 | 39 | I prefer my time to be in AM/PM, so this script just watches for keypress on a textarea, and if the time matches the current time (in 24 hour format), 40 | it updates the value to AM/PM 41 | 42 | Todo: 43 | - Support multiple time values in the same text area 44 | - Probably a clean way to look for textarea? (currently uses MutationObserver) 45 | 46 | 47 | ------ 48 | 49 | The old theme I used was from https://github.com/apg-dev/roam-theme-bear, with colors have been tweaked. It does not work very well & has been removed 50 | -------------------------------------------------------------------------------- /roam-live-preview.user.js: -------------------------------------------------------------------------------- 1 | // ==UserScript== 2 | // @name Roam live preview 3 | // @namespace http://tampermonkey.net/ 4 | // @version 0.2 5 | // @description Live preview for page refs on hover 6 | // @author palashkaria 7 | // @match https://roamresearch.com 8 | // @downloadURL https://raw.github.com/palashkaria/roam-modifiers/master/roam-live-preview.user.js 9 | // @grant none 10 | // ==/UserScript== 11 | 12 | (function () { 13 | 'use strict'; 14 | const runInPageContext = (method, ...args) => { 15 | // will be parsed as a function object. 16 | console.log(method); 17 | console.log(args); 18 | const stringifiedMethod = method.toString(); 19 | 20 | const stringifiedArgs = JSON.stringify(args); 21 | 22 | const scriptContent = `document.currentScript.innerHTML = JSON.stringify((${stringifiedMethod})(...${stringifiedArgs}));`; 23 | 24 | const scriptElement = document.createElement('script'); 25 | scriptElement.innerHTML = scriptContent; 26 | document.documentElement.prepend(scriptElement); 27 | 28 | const result = JSON.parse(scriptElement.innerHTML); 29 | document.documentElement.removeChild(scriptElement); 30 | console.log(result); 31 | return result; 32 | }; 33 | const getBlockById = (dbId) => { 34 | const fn = function (dbId) { 35 | return function (dbId, ...args) { 36 | return window.roamAlphaAPI.pull(...args, '[*]', dbId); 37 | }; 38 | }; 39 | return runInPageContext(fn(dbId), dbId); 40 | }; 41 | 42 | const queryFn = (query, ...params) => { 43 | return runInPageContext( 44 | function (...args) { 45 | return window.roamAlphaAPI.q(...args); 46 | }, 47 | query, 48 | ...params 49 | ); 50 | }; 51 | 52 | const queryFirst = (query, ...params) => { 53 | const results = queryFn(query, ...params); 54 | if (!results || !results[0] || results[0].length < 1) return null; 55 | 56 | return getBlockById(results[0][0]); 57 | }; 58 | const baseUrl = () => { 59 | // https://roamresearch.com/#/app/roam-toolkit/page/03-24-2020 60 | const url = new URL(window.location.href); 61 | const parts = url.hash.split('/'); 62 | 63 | url.hash = parts.slice(0, 3).concat(['page']).join('/'); 64 | return url; 65 | }; 66 | const getPageByName = (name) => { 67 | return queryFirst('[:find ?e :in $ ?a :where [?e :node/title ?a]]', name); 68 | }; 69 | const getPageUrlByName = (name) => { 70 | const page = getPageByName(name); 71 | return getPageUrl(page[':block/uid']); 72 | }; 73 | const getPageUrl = (uid) => { 74 | return baseUrl().toString() + '/' + uid; 75 | }; 76 | 77 | const createPreviewIframe = () => { 78 | const iframe = document.createElement('iframe'); 79 | const url = getPageUrl('search'); 80 | const isAdded = (pageUrl) => !!document.querySelector(`[src="${pageUrl}"]`); 81 | if (isAdded(url)) { 82 | return; 83 | } 84 | iframe.src = url; 85 | iframe.style.position = 'absolute'; 86 | iframe.style.left = '0'; 87 | iframe.style.top = '0'; 88 | iframe.style.opacity = '0'; 89 | iframe.style.pointerEvents = 'none'; 90 | 91 | iframe.style.height = '0'; 92 | iframe.style.width = '0'; 93 | iframe.style.border = '0'; 94 | iframe.style.boxShadow = '0 0 4px 5px rgba(0, 0, 0, 0.2)'; 95 | iframe.style.borderRadius = '4px'; 96 | iframe.id = 'roam-toolkit-preview-iframe'; 97 | 98 | const styleNode = document.createElement('style'); 99 | styleNode.innerHTML = ` 100 | .roam-topbar { 101 | display: none !important; 102 | } 103 | .roam-body-main { 104 | top: 0px !important; 105 | } 106 | #buffer { 107 | display: none !important; 108 | } 109 | iframe { 110 | display: none !important; 111 | } 112 | `; 113 | iframe.onload = (event) => { 114 | event.target.contentDocument.body.appendChild(styleNode); 115 | }; 116 | document.body.appendChild(iframe); 117 | const htmlElement = document.querySelector('html'); 118 | if (htmlElement) { 119 | // to reset scroll after adding iframe 120 | htmlElement.scrollTop = 0; 121 | } 122 | return iframe; 123 | }; 124 | const enableLivePreview = () => { 125 | let hoveredElement = null; 126 | let popupTimeout = null; 127 | let popper = null; 128 | const previewIframe = createPreviewIframe(); 129 | 130 | document.addEventListener('mouseover', (e) => { 131 | const target = e.target; 132 | const isPageRef = target.classList.contains('rm-page-ref'); 133 | const isPageRefTag = target.classList.contains('rm-page-ref-tag'); 134 | // remove '#' for page tags 135 | const text = isPageRefTag ? target.innerText.slice(1) : target.innerText; 136 | if (isPageRef) { 137 | hoveredElement = target; 138 | const url = getPageUrlByName(text); 139 | const isAdded = (pageUrl) => 140 | !!document.querySelector(`[src="${pageUrl}"]`); 141 | const isVisible = (pageUrl) => 142 | document.querySelector(`[src="${pageUrl}"]`).style.opacity === '1'; 143 | if ((!isAdded(url) || !isVisible(url)) && previewIframe) { 144 | previewIframe.src = url; 145 | previewIframe.style.height = '500px'; 146 | previewIframe.style.width = '500px'; 147 | previewIframe.style.pointerEvents = 'none'; 148 | } 149 | if (!popupTimeout) { 150 | popupTimeout = window.setTimeout(() => { 151 | if (previewIframe) { 152 | previewIframe.style.opacity = '1'; 153 | previewIframe.style.pointerEvents = 'all'; 154 | 155 | popper = window.Popper.createPopper(target, previewIframe, { 156 | placement: 'right', 157 | modifiers: [ 158 | { 159 | name: 'preventOverflow', 160 | options: { 161 | padding: { top: 48 }, 162 | }, 163 | }, 164 | { 165 | name: 'flip', 166 | options: { 167 | boundary: document.querySelector('#app'), 168 | }, 169 | }, 170 | ], 171 | }); 172 | } 173 | }, 300); 174 | } 175 | } 176 | }); 177 | document.addEventListener('mouseout', (e) => { 178 | const target = e.target; 179 | const relatedTarget = e.relatedTarget; 180 | const iframe = document.getElementById('roam-toolkit-preview-iframe'); 181 | if ( 182 | (hoveredElement === target && relatedTarget !== iframe) || 183 | (target === iframe && relatedTarget !== hoveredElement) || 184 | !document.body.contains(hoveredElement) 185 | ) { 186 | hoveredElement = null; 187 | clearTimeout(popupTimeout); 188 | popupTimeout = null; 189 | if (iframe) { 190 | if (iframe.contentDocument) { 191 | // scroll to top when removed 192 | const scrollContainer = iframe.contentDocument.querySelector( 193 | '.roam-center > div' 194 | ); 195 | if (scrollContainer) { 196 | scrollContainer.scrollTop = 0; 197 | } 198 | } 199 | iframe.style.pointerEvents = 'none'; 200 | iframe.style.opacity = '0'; 201 | iframe.style.height = '0'; 202 | iframe.style.width = '0'; 203 | } 204 | if (popper) { 205 | popper.destroy(); 206 | popper = null; 207 | } 208 | } else { 209 | console.log('out', target, event); 210 | } 211 | }); 212 | }; 213 | var remoteScript = document.createElement('script'); 214 | remoteScript.src = 215 | 'https://unpkg.com/@popperjs/core@2/dist/umd/popper.js?ts=' + +new Date(); 216 | remoteScript.onload = enableLivePreview; 217 | document.body.appendChild(remoteScript); 218 | })(); 219 | -------------------------------------------------------------------------------- /roam-mappletons-andy-subdued.css: -------------------------------------------------------------------------------- 1 | /* Make sure you have the fonts Lato and Open Sans installed locally on your machine. 2 | They're free to download from Google: 3 | https://fonts.google.com/specimen/Lato 4 | https://fonts.google.com/specimen/Open+Sans */ 5 | h1, 6 | h2, 7 | h3, 8 | h4, 9 | h5, 10 | h6 { 11 | font-family: 'Lato', sans-serif; 12 | } 13 | 14 | 15 | div, 16 | textarea { 17 | font-family: 'Open Sans'; 18 | } 19 | .roam-topbar { 20 | background: transparent; 21 | } 22 | .roam-body { 23 | background-color: #fcfcfc; 24 | } 25 | .roam-block-container { 26 | max-width: 1000px; 27 | } 28 | 29 | .rm-query { 30 | border: 0.5px solid #e4e9ec; 31 | border-radius: 5px; 32 | } 33 | 34 | .rm-query .rm-query-title { 35 | background-color: #f7f8f8; 36 | padding: 0.8em; 37 | color: #d1dbe2; 38 | font-size: 80%; 39 | } 40 | 41 | .rm-reference-main.rm-query-content { 42 | padding: 0.8em; 43 | } 44 | 45 | .rm-reference-main .rm-reference-item .rm-block-text { 46 | font-size: 90%; 47 | } 48 | 49 | .rm-reference-main .rm-reference-item .controls { 50 | margin-left: -1em; 51 | } 52 | 53 | .rm-ref-page-view { 54 | padding: 0.4em 0.2em; 55 | } 56 | 57 | .roam-body .roam-app .roam-sidebar-container .roam-sidebar-content .starred-pages-wrapper .starred-pages .page { 58 | padding: 6px; 59 | } 60 | 61 | div.flex-v-box.starred-pages-wrapper > div.flex-h-box > span { 62 | font-size: 14px; 63 | opacity: 80%; 64 | letter-spacing: 0.04em; 65 | } 66 | 67 | div.roam-sidebar-container.noselect > div > div { 68 | font-size: 14px; 69 | letter-spacing: 0.03em; 70 | } 71 | 72 | #block-input { 73 | background: white; 74 | } 75 | 76 | .roam-body #block-input > span > div { 77 | padding: 6px 24px; 78 | background: white; 79 | } 80 | 81 | span.bp3-icon-small.bp3-icon-star { 82 | display: none; 83 | visibility: hidden; 84 | } 85 | 86 | .roam-block { 87 | max-width: 850px; 88 | } 89 | 90 | #right-sidebar > div { 91 | background-color: #fcfcfc; 92 | border-left: 1px solid #e9ebef; 93 | } 94 | 95 | .controls .simple-bullet-outer .simple-bullet-inner { 96 | background-color: #dde2ee; 97 | } 98 | .block-border-left { 99 | border-left: 1px solid #dbdbdb; 100 | } 101 | .kanban-board { 102 | background-color: #fcfcfc; 103 | } 104 | .kanban-card { 105 | background-color: white; 106 | margin: 8px; 107 | box-shadow: 0px 1px 2px #9EB3C0; 108 | padding: 10px; 109 | border-radius: 2px; 110 | line-height: 1.3em; 111 | } 112 | .kanban-title { 113 | text-align: center; 114 | font-weight: bold; 115 | padding-top: 6px; 116 | } 117 | .kanban-column { 118 | background-color: #E4EDF2; 119 | margin: 0px 4px 0px 4px; 120 | padding: 4px; 121 | min-width: 200px; 122 | border-radius: 3px; 123 | } 124 | 125 | .checkmark { 126 | background: #fff; 127 | } 128 | .check-container input:checked ~ .checkmark { 129 | background: #33bdea; 130 | } 131 | .check-container input:checked ~ .checkmark:after { 132 | border-color: #fff; 133 | } 134 | .rm-reference-item { 135 | margin-top: 8px; 136 | border-radius: 6px; 137 | border: 1px solid #e4e9ee; 138 | margin-right: 8px; 139 | flex: 1 1 100%; 140 | word-break: break-word; 141 | background-color: #f5f7fa; 142 | padding: 8px; 143 | } 144 | 145 | .rm-level2 { 146 | font-size: 1.5em; 147 | } 148 | .rm-level3 { 149 | color: #939aae; 150 | font-weight: 400; 151 | font-size: 1.3em; 152 | } 153 | .rm-page-ref { 154 | color: #9aabd0; 155 | } 156 | .rm-page-ref-link-color { 157 | color: #4d94ff; 158 | font-weight: 600; 159 | } 160 | a { 161 | color: #8A3CC8; 162 | } 163 | .intercom-app, 164 | .intercom-launcher-frame, 165 | #intercom-container { 166 | display: none; 167 | } 168 | .roam-body .roam-app .roam-sidebar-container { 169 | background-color: #fafafa; 170 | border-right: 1px #eee solid; 171 | } 172 | .roam-body .roam-app .roam-sidebar-container .roam-sidebar-content .starred-pages-wrapper .starred-pages .page, 173 | .roam-body .roam-app .roam-sidebar-container > * { 174 | opacity: 80%; 175 | box-shadow: none; 176 | } 177 | .roam-body .roam-app .roam-sidebar-container .roam-sidebar-content .starred-pages-wrapper .starred-pages .page:hover, 178 | .roam-body .roam-app .roam-sidebar-container .roam-sidebar-content .log-button:hover { 179 | background: white; 180 | color: black; 181 | opacity: 100%; 182 | } 183 | #buffer.tall { 184 | height: calc(100vh - 50px); 185 | } 186 | 187 | .check-container { 188 | padding-right: 4px; 189 | } 190 | span.rm-page-ref { 191 | border-radius: 2px; 192 | padding-left: 1px; 193 | padding-right: 1px; 194 | } 195 | .content span.rm-page-ref { 196 | padding: 4px 1px 1px; 197 | /* required for fixing azo */ 198 | } 199 | .center-proj { 200 | text-align: center; 201 | } 202 | 203 | 204 | /* Custom data tags */ 205 | span.rm-page-ref[data-tag="TwitterPost"] { 206 | background: #81D5ED; 207 | color: white; 208 | padding: 3px 7px; 209 | line-height: 2em; 210 | font-weight: 500; 211 | } 212 | 213 | span.rm-page-ref[data-tag="Literature Notes"] { 214 | background: #9769FF; 215 | color: white; 216 | padding: 3px 7px; 217 | font-weight: 500; 218 | line-height: 2em; 219 | } 220 | 221 | 222 | span.rm-page-ref[data-tag="Evergreens"] { 223 | background: #0DBAC6; 224 | color: #fff; 225 | padding: 3px 8px; 226 | line-height: 2em; 227 | font-weight: 500; 228 | } 229 | 230 | span.rm-page-ref[data-tag="Seedling"] { 231 | color: #0dbac6; 232 | padding: 3px 3px; 233 | font-weight: 600; 234 | line-height: 1.4em; 235 | } 236 | 237 | span.rm-page-ref[data-tag="Idea Bank"] { 238 | color: #FCB815; 239 | padding: 3px 4px; 240 | font-weight: 700; 241 | line-height: 1.4em; 242 | } 243 | 244 | span.rm-page-ref[data-tag="Idea Bank"]:before { 245 | content: '✦ ' 246 | } 247 | 248 | span.rm-page-ref[data-tag="Illustrated Notes"] { 249 | color: #7172FC; 250 | padding: 3px 4px; 251 | font-weight: 700; 252 | line-height: 1.4em; 253 | } 254 | 255 | span.rm-page-ref[data-tag="Garden Notes"] { 256 | color: #9DBC13; 257 | padding: 3px 4px; 258 | font-weight: 700; 259 | line-height: 1.4em; 260 | } 261 | 262 | span.rm-page-ref[data-tag="Video Tutorial"] { 263 | color: #db3b8d; 264 | padding: 3px 4px; 265 | line-height: 1.4em; 266 | font-weight: 700; 267 | } 268 | 269 | span.rm-page-ref[data-tag="Essay"] { 270 | background: #ADCB2A; 271 | color: #fff; 272 | padding: 3px 7px; 273 | line-height: 2em; 274 | font-weight: 500; 275 | } 276 | 277 | 278 | span.rm-page-ref[data-tag="Livestream"] { 279 | color: #B979CF; 280 | padding: 3px 4px; 281 | line-height: 1.4em; 282 | font-weight: 700; 283 | } 284 | 285 | span.rm-page-ref[data-tag="Talk"] { 286 | background: #7172FC; 287 | color: #fff; 288 | padding: 3px 7px; 289 | line-height: 2em; 290 | font-weight: 500; 291 | } 292 | 293 | span.rm-page-ref[data-tag="Waiting"] { 294 | background: #F9C866; 295 | color: #fff; 296 | padding: 3px 7px; 297 | line-height: 2em; 298 | font-weight: 500; 299 | } 300 | 301 | span.rm-page-ref[data-tag="Researching"] { 302 | background: #FF9D66; 303 | color: #fff; 304 | padding: 3px 7px; 305 | line-height: 2em; 306 | font-weight: 500; 307 | } 308 | 309 | span.rm-page-ref[data-tag="Synthesising"] { 310 | background: #FC766F; 311 | color: #fff; 312 | padding: 3px 7px; 313 | line-height: 2em; 314 | font-weight: 500; 315 | } 316 | 317 | 318 | span.rm-page-ref[data-tag="Alive"] { 319 | background: #EE5F85; 320 | color: #fff; 321 | padding: 3px 7px; 322 | line-height: 2em; 323 | font-weight: 500; 324 | } 325 | 326 | /* Andy Matuschak */ 327 | .roam-center { 328 | flex: 1 1 100% !important; 329 | flex-basis: 50% !important; 330 | } 331 | 332 | #right-sidebar { 333 | background-color: white !important; 334 | } 335 | 336 | #right-sidebar #roam-right-sidebar-content { 337 | overflow: scroll !important; 338 | white-space: normal; 339 | display: flex; 340 | align-content: flex-start; 341 | /* Below is for masonry layout */ 342 | flex-flow: column wrap; 343 | } 344 | 345 | #right-sidebar #roam-right-sidebar-content > div { 346 | display: flex; 347 | flex: 0 1 auto; 348 | flex-direction: column; 349 | padding: 10px; 350 | border: 0.5px solid #e4e9ec !important; 351 | border-radius: 5px; 352 | background-color: white !important; 353 | align-self: flex-start; 354 | margin-right: 0px !important; 355 | /* Below is for masonry layout */ 356 | margin-bottom: 16px; 357 | min-height: fit-content; 358 | max-width: 600px 359 | } 360 | 361 | #right-sidebar #roam-right-sidebar-content > div > div:nth-child(2) { 362 | resize: vertical; 363 | overflow-y: auto; 364 | overflow-x: hidden; 365 | max-height: 780px; 366 | } 367 | 368 | .roam-log-container .roam-log-page { 369 | padding: 10px; 370 | border-top: 1px solid #dbdbdb; 371 | } 372 | /* modifications begin */ 373 | 374 | 375 | /* sidebar magic 🔥 :) 376 | * resets the padding changes when sidebar is visible. 377 | * This allows the sidebar to overlay the content, instead of pushing it. 378 | * on click, the content gets pushed (as expected) 379 | * ~ is the sibling CSS selector; to detect the closed state of the sidebar 380 | */ 381 | .roam-sidebar-container:not([style^='left: 0px; top: 0px; bottom: 0px;']) ~ .roam-main .roam-body-main { 382 | width: 100vw !important; 383 | } 384 | 385 | .roam-sidebar-container:not([style^='left: 0px; top: 0px; bottom: 0px;']) ~ .roam-main .roam-body-main > .roam-center > div:first-child { 386 | padding-right: calc((100% - 800px) / 2) !important; 387 | padding-left: calc((100% - 800px) / 2) !important; 388 | } 389 | 390 | /* Prevents weird siderbar scroll */ 391 | html { 392 | overflow: hidden; 393 | } 394 | 395 | /* more sidebar fixes */ 396 | 397 | /* makes the shortcuts stick edge-to-edge, 398 | * with spacing on the left 399 | */ 400 | .starred-pages-wrapper { 401 | padding: 8px 0 !important; 402 | } 403 | 404 | .roam-body .roam-app .roam-sidebar-container .roam-sidebar-content .starred-pages-wrapper .starred-pages .page, 405 | .starred-pages-wrapper > div.flex-h-box { 406 | padding-left: 20px; 407 | } 408 | 409 | /* 410 | * ⌗ for block refs 🚀 411 | */ 412 | .rm-block-ref::before { 413 | content: '⌗'; 414 | display: inline-block; 415 | color: #4d94ff; 416 | margin-right: 5px; 417 | top: -2px; 418 | position: relative; 419 | } 420 | .rm-block-ref { 421 | display: inline-flex; 422 | border-bottom: none; 423 | font-size: 1em; 424 | color: #627a9d; 425 | background-color: #f5f7fa; 426 | } 427 | 428 | .rm-block-ref:hover { 429 | cursor: pointer; 430 | } 431 | 432 | 433 | /* Scrollbar improvements */ 434 | div::-webkit-scrollbar-track { 435 | background-color: #fcfcfc!important; 436 | } 437 | 438 | div::-webkit-scrollbar-thumb { 439 | background-color: #d1dbe2 !important; 440 | } 441 | 442 | /* OSX-like scrollbars 🤓 (width increases on hover) 443 | * default width is 6px - increases to 8px on hover 444 | * spacing around is 2px (defined by the same-colored border) 445 | */ 446 | div::-webkit-scrollbar { 447 | width: 10px; 448 | height: 10px; 449 | border-radius: 20px; 450 | } 451 | div::-webkit-scrollbar-track { 452 | background: transparent; 453 | border-radius: 20px; 454 | } 455 | div::-webkit-scrollbar-thumb { 456 | background-color: #d1dbe2; 457 | border: 3px #fcfcfc solid; 458 | border-radius: 20px; 459 | } 460 | div::-webkit-scrollbar-thumb:hover { 461 | background-color: rgba(0, 0, 0, 0.4); 462 | border: 2px #fcfcfc solid; 463 | } 464 | 465 | 466 | #buffer { 467 | z-index: 1; 468 | } 469 | 470 | #buffer > div > div::-webkit-scrollbar-track { 471 | background-color: #2f3537 !important; 472 | } 473 | 474 | 475 | #buffer > div > div::-webkit-scrollbar-thumb { 476 | background-color: #d1dbe2 !important; 477 | } 478 | 479 | /* hover scrollbar */ 480 | #buffer > div > div::-webkit-scrollbar { 481 | width: 10px; 482 | height: 10px; 483 | border-radius: 20px; 484 | } 485 | #buffer > div > div::-webkit-scrollbar-track { 486 | background: transparent; 487 | border-radius: 20px; 488 | } 489 | #buffer > div > div::-webkit-scrollbar-thumb { 490 | background-color: #d1dbe2; 491 | border: 3px #2f3537 solid; 492 | border-radius: 20px; 493 | } 494 | #buffer > div > div::-webkit-scrollbar-thumb:hover { 495 | background-color: rgba(0, 0, 0, 0.4); 496 | border: 2px #2f3537 solid; 497 | } 498 | 499 | /* other modifications */ 500 | 501 | .roam-bullet-closed { 502 | color: #a7bbc8; 503 | } 504 | 505 | .rm-page-ref-brackets { 506 | opacity: 0.4; 507 | } 508 | 509 | 510 | .block-highlight-yellow { 511 | background-color: #ffec99; 512 | } 513 | -------------------------------------------------------------------------------- /roam-sidebar-modifier.css: -------------------------------------------------------------------------------- 1 | /* sidebar hover magic 🔥 :) 2 | * resets the padding changes when sidebar is visible. 3 | * This allows the sidebar to overlay the content, instead of pushing it. 4 | * on click, the content gets pushed (as expected) 5 | * ~ is the sibling CSS selector; to detect the closed state of the sidebar 6 | */ 7 | .roam-sidebar-container:not([style^='left: 0px; top: 0px; bottom: 0px;']) ~ .roam-main .roam-body-main { 8 | width: 100vw !important; 9 | } 10 | 11 | .roam-sidebar-container:not([style^='left: 0px; top: 0px; bottom: 0px;']) ~ .roam-main .roam-body-main > .roam-center > div:first-child { 12 | padding-right: calc((100% - 800px) / 2) !important; 13 | padding-left: calc((100% - 800px) / 2) !important; 14 | } 15 | 16 | /* Prevents weird siderbar scroll */ 17 | html { 18 | overflow: hidden; 19 | } 20 | 21 | /* more sidebar fixes */ 22 | 23 | /* makes the shortcuts stick edge-to-edge, 24 | * with spacing on the left 25 | */ 26 | .starred-pages-wrapper { 27 | padding: 8px 0 !important; 28 | } 29 | 30 | .roam-body .roam-app .roam-sidebar-container .roam-sidebar-content .starred-pages-wrapper .starred-pages .page, 31 | .starred-pages-wrapper > div.flex-h-box { 32 | padding-left: 20px; 33 | } 34 | -------------------------------------------------------------------------------- /roam-sticky-sidebar.css: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | use variables to control colors, size. 4 | delete the part below comment to remove any behaviour 5 | **/ 6 | :root { 7 | /** update colors for dark themes here */ 8 | --roamer-sb-bg: #f7f8fa; 9 | --roamer-sb-card-bg: white; 10 | --roamer-sb-card-border: #e4e9ec; 11 | --roamer-sb-card-width: 600px; 12 | /* leave blank for no prefix */ 13 | --roamer-sb-card-page-prefix: "Page "; 14 | } 15 | 16 | .roam-center { 17 | /* sidebar-to-content-ratio */ 18 | flex-basis: 50% !important; 19 | } 20 | 21 | 22 | #right-sidebar > div { 23 | background-color: var(--roamer-sb-bg); 24 | } 25 | /* sidebar layout */ 26 | #right-sidebar #roam-right-sidebar-content { 27 | overflow: auto !important; 28 | white-space: normal; 29 | display: flex; 30 | align-content: flex-start; 31 | flex-direction: row; 32 | height: 100% 33 | } 34 | 35 | #right-sidebar #roam-right-sidebar-content > div { 36 | min-width: var(--roamer-sb-card-width); 37 | background-color: var(--roamer-sb-card-bg); 38 | border: 1px solid var(--roamer-sb-card-border) !important; 39 | /* card layout */ 40 | display: flex; 41 | flex-direction: column; 42 | padding: 12px; 43 | border-radius: 4px; 44 | align-self: flex-start; 45 | margin-right: 0px !important; 46 | height: 100% !important; 47 | } 48 | 49 | #right-sidebar #roam-right-sidebar-content > div > div:nth-child(2) { 50 | /* adds scrollbar to card content */ 51 | overflow: auto; 52 | padding: 0 8px 8px 8px !important; 53 | } 54 | 55 | /* sticky */ 56 | #right-sidebar #roam-right-sidebar-content > div { 57 | position: sticky; 58 | left: 16px 59 | } 60 | 61 | /* page numbers */ 62 | #right-sidebar #roam-right-sidebar-content { 63 | counter-reset: page; 64 | } 65 | #right-sidebar #roam-right-sidebar-content > div > div:nth-child(1):before { 66 | counter-increment: page; 67 | content: var(--roamer-sb-card-page-prefix) counter(page); 68 | padding: 0px 4px; 69 | display: flex; 70 | align-items: center; 71 | z-index: 1; 72 | } 73 | 74 | /** brings card to top on focus */ 75 | #right-sidebar #roam-right-sidebar-content > div:focus-within { 76 | z-index: 100; 77 | } 78 | -------------------------------------------------------------------------------- /time-format.user.js: -------------------------------------------------------------------------------- 1 | // ==UserScript== 2 | // @name Roam Current time format 3 | // @namespace http://tampermonkey.net/ 4 | // @version 0.2 5 | // @description use AM/PM format for /currentTime command in Roam Research 6 | // @downloadURL https://raw.github.com/palashkaria/roam-modifiers/master/time-format.user.js 7 | // @author palashkaria 8 | // @match https://roamresearch.com/* 9 | // @grant none 10 | // ==/UserScript== 11 | 12 | (function () { 13 | 'use strict'; 14 | 15 | function formatAMPM(date) { 16 | var hours = date.getHours(); 17 | var minutes = date.getMinutes(); 18 | var ampm = hours >= 12 ? 'PM' : 'AM'; 19 | hours = hours % 12; 20 | hours = hours ? hours : 12; // the hour '0' should be '12' 21 | minutes = minutes < 10 ? '0' + minutes : minutes; 22 | var strTime = hours + ':' + minutes + ' ' + ampm; 23 | return strTime; 24 | } 25 | function replaceTime(mutations) { 26 | var textarea = document.querySelector('textarea'); 27 | if (textarea) { 28 | textarea.addEventListener('keydown', (data) => { 29 | console.log('value', data.target.value); 30 | var currentDate = new Date(); 31 | var currentTime = currentDate 32 | .toLocaleTimeString() 33 | .split(':') 34 | .splice(0, 2) 35 | .join(':'); 36 | var currentTimeFormatted = formatAMPM(currentDate); 37 | console.log( 38 | 'value', 39 | data.target.value, 40 | currentTimeFormatted, 41 | currentTime 42 | ); 43 | if (currentTime === data.target.value) { 44 | console.log('yas!'); 45 | document.querySelector('textarea').value = currentTimeFormatted; 46 | } 47 | }); 48 | } 49 | } 50 | var target = document.querySelector('body'); 51 | 52 | // create an observer instance 53 | var observer = new MutationObserver(function (mutations) { 54 | replaceTime(mutations); 55 | mutations.forEach(function (mutation) { 56 | console.log(mutation.type); 57 | }); 58 | }); 59 | 60 | // configuration of the observer: 61 | var config = { attributes: true, childList: true, characterData: true }; 62 | 63 | // pass in the target node, as well as the observer options 64 | observer.observe(target, config); 65 | })(); 66 | --------------------------------------------------------------------------------