Last active
September 5, 2025 13:53
-
-
Save jwc20/ff047e804bb6bdce975e51a7afb82039 to your computer and use it in GitHub Desktop.
my Ubersicht widget for displaying Things task
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
| Display current task on screen using: https://tracesof.net/uebersicht/ | |
| Current tasks are made using: https://culturedcode.com/things/ |
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
| refreshFrequency: 60000 | |
| # homeDir = process.env['HOME'] | |
| # sqliteDb = homeDir + '/Library/Containers/com.culturedcode.things/Data/Library/Application\ Support/Cultured\ Code/Things/ThingsLibrary.db' | |
| sqliteDb = '/Users/cjw/Library/Group Containers/JLMPQHK86H.com.culturedcode.ThingsMac/ThingsData-DC8DV/Things Database.thingsdatabase/main.sqlite' | |
| #todaySql = 'select ZTITLE from ZTHING where ZTRASHED=0 AND ZSTATUS=0 AND ZFOCUSLEVEL IS NULL AND ZSCHEDULER =1 AND ZSTART==1 AND ZTYPE=0 ORDER BY ZTITLE ASC' | |
| # todaySql = 'select title from TMTask where trashed=0 AND status=0 AND start=1 AND type=0 AND todayIndex<>0 ORDER BY todayIndex asc limit 1' | |
| todaySql = 'SELECT title FROM TMTask WHERE trashed = 0 AND status = 0 AND start = 1 AND type = 0 AND todayIndex <> 0 AND title IS NOT NULL AND title<>"" ORDER BY todayIndex ASC LIMIT 1' | |
| command: "sqlite3 '#{sqliteDb}' '#{todaySql}' | awk 'BEGIN {print \"\"} {print substr($0,0)\"<br />\"} /^[*]/ {print \"<blockquote><li>\"substr($0,2)\"</li></blockquote>\"} END {print \"\"}'" | |
| style: """ | |
| border-radius: 6px | |
| padding: 0px 20px | |
| top: 1.6rem | |
| left: 0.8rem | |
| color: #fff | |
| font-family: 'JetBrainsMono Nerd Font' | |
| text-align: center | |
| .datetime | |
| font-size: 14px | |
| color: #ffd700 | |
| opacity: 0.8 | |
| .timer-button | |
| background: none | |
| border: none | |
| color: #ffd700 | |
| font-size: 14px | |
| cursor: pointer | |
| opacity: 0.8 | |
| transition: opacity 0.2s | |
| font-family: 'JetBrainsMono Nerd Font' | |
| .timer-button:hover | |
| opacity: 1 | |
| h | |
| display: block | |
| text-align: center | |
| font-size: 24px | |
| font-weight: 100 | |
| div | |
| display: block | |
| ol | |
| padding-left: 20px | |
| .things_icon | |
| float:left | |
| .stopwatch | |
| font-size: 14px | |
| color: #ffd700 | |
| font-family: 'JetBrainsMono Nerd Font' | |
| opacity: 0.8 | |
| .container | |
| position: fixed | |
| top: 0.14rem | |
| .stopwatch-container | |
| position: fixed | |
| right: 1.8rem | |
| display: flex | |
| align-items: center | |
| gap: 10px | |
| .things-container | |
| position: fixed | |
| left: 1.8rem | |
| transform: none | |
| display: flex | |
| align-items: center | |
| justify-content: flex-start | |
| gap: 5px | |
| z-index: 1000 | |
| width: auto | |
| min-width: 300px | |
| max-width: 80vw | |
| background: none | |
| box-shadow: none | |
| border: none | |
| padding: 0 | |
| margin: 0 | |
| pointer-events: none | |
| /* Ensures it stays above other content */ | |
| /* Adjust as needed for your layout */ | |
| .thingslist | |
| font-size: 14px | |
| white-space: nowrap | |
| text-overflow: ellipsis | |
| color: #fff | |
| .completed | |
| color: #888 | |
| font-weight: regular | |
| text-decoration:line-through | |
| .current-tasks-label | |
| font-size: 15px | |
| white-space: nowrap | |
| text-overflow: ellipsis | |
| font-style: italic | |
| font-weight: 100 | |
| color: #ffd700 | |
| .current-tasks-label-arrow | |
| font-size: 17px | |
| white-space: nowrap | |
| font-weight: bold | |
| color: #ffd700 | |
| """ | |
| # render: -> """ | |
| # <div class='container'> | |
| # <div class='stopwatch-container'> | |
| # <div class='datetime'></div> | |
| # <div class='stopwatch'>00:00:00</div> | |
| # <button class='timer-button' id='startPause'></button> | |
| # <button class='timer-button' id='reset'></button> | |
| # </div> | |
| # <div class='things-container'> | |
| # <div class='current-tasks-label'>Current Task</div> | |
| # <div class='current-tasks-label-arrow' style='letter-spacing: 0.5em;'>=></div> | |
| # <div class='thingslist'></div> | |
| # </div> | |
| # </div> | |
| # """ | |
| render: -> """ | |
| <div class='container'> | |
| <div class='stopwatch-container'> | |
| <div class='datetime'></div> | |
| </div> | |
| <div class='things-container'> | |
| <div class='current-tasks-label'>Current Task</div> | |
| <div class='current-tasks-label-arrow' style='letter-spacing: 0.5em;'>=></div> | |
| <div class='thingslist'></div> | |
| </div> | |
| </div> | |
| """ | |
| update: (output, domEl) -> | |
| $(domEl).find('.thingslist').html(output) | |
| afterRender: (domEl) -> | |
| getPlanetarySymbol = (day) -> | |
| symbols = { | |
| 0: '☉', # Sunday | |
| 1: '☽', # Monday | |
| 2: '♂', # Tuesday | |
| 3: '☿', # Wednesday | |
| 4: '♃', # Thursday | |
| 5: '♀', # Friday | |
| 6: '♄' # Saturday | |
| } | |
| symbols[day] | |
| getDotPattern = (currentDay) -> | |
| dots = [] | |
| for i in [0..6] | |
| dots.push(if i == currentDay then '●' else '○') | |
| dots.join(' ') | |
| getDayOfWeek = (day) -> | |
| days = { | |
| 0: 'Sunday', | |
| 1: 'Monday', | |
| 2: 'Tuesday', | |
| 3: 'Wednesday', | |
| 4: 'Thursday', | |
| 5: 'Friday', | |
| 6: 'Saturday', | |
| } | |
| days[day] | |
| updateDateTime = -> | |
| now = new Date() | |
| year = now.getFullYear() | |
| month = (now.getMonth() + 1).toString().padStart(2, '0') | |
| day = now.getDate().toString().padStart(2, '0') | |
| hours = now.getHours() | |
| minutes = now.getMinutes().toString().padStart(2, '0') | |
| ampm = if hours >= 12 then 'PM' else 'AM' | |
| hours = hours % 12 | |
| hours = hours ? 12 # Convert 0 to 12 | |
| hours = hours.toString().padStart(2, '0') # Ensure two digits | |
| # planetarySymbol = getPlanetarySymbol(now.getDay()) | |
| dayOfWeek = getDayOfWeek(now.getDay()) | |
| # dotPattern = getDotPattern(now.getDay()) | |
| $(domEl).find('.datetime').html("「#{hours}.#{minutes}#{ampm} | #{year}-#{month}-#{day} | #{dayOfWeek}」") | |
| updateDateTime() | |
| setInterval(updateDateTime, 60000) # Update every minute | |
| startTime = null | |
| isRunning = false | |
| elapsedTime = 0 | |
| timerInterval = null | |
| updateTimer = -> | |
| if isRunning | |
| currentTime = new Date() | |
| diff = currentTime - startTime + elapsedTime | |
| hours = Math.floor(diff / 3600000) | |
| minutes = Math.floor((diff % 3600000) / 60000) | |
| seconds = Math.floor((diff % 60000) / 1000) | |
| timeString = "#{hours.toString().padStart(2, '0')}:#{minutes.toString().padStart(2, '0')}:#{seconds.toString().padStart(2, '0')}" | |
| $(domEl).find('.stopwatch').html(timeString) | |
| startPauseTimer = -> | |
| if isRunning | |
| isRunning = false | |
| elapsedTime += new Date() - startTime | |
| clearInterval(timerInterval) | |
| $(domEl).find('#startPause').html('') | |
| else | |
| isRunning = true | |
| startTime = new Date() | |
| timerInterval = setInterval(updateTimer, 1000) | |
| $(domEl).find('#startPause').html('') | |
| resetTimer = -> | |
| isRunning = false | |
| startTime = null | |
| elapsedTime = 0 | |
| clearInterval(timerInterval) | |
| $(domEl).find('.stopwatch').html('00:00:00') | |
| $(domEl).find('#startPause').html('') | |
| $(domEl).find('#startPause').on 'click', startPauseTimer | |
| $(domEl).find('#reset').on 'click', resetTimer |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment