Skip to content

Instantly share code, notes, and snippets.

@foeken
Last active June 16, 2025 06:26
Show Gist options
  • Save foeken/cd809018e6caf846d174f656bb30109c to your computer and use it in GitHub Desktop.
Save foeken/cd809018e6caf846d174f656bb30109c to your computer and use it in GitHub Desktop.
Tana CSS (mar16)
#!/bin/zsh
# Required parameters:
# @raycast.schemaVersion 1
# @raycast.title Tana Custom CSS Patch
# @raycast.mode compact
# Optional parameters:
# @raycast.icon 🚧
# @raycast.packageName Tana
# Documentation:
# @raycast.author dreetje
# @raycast.authorURL https://raycast.com/dreetje
# @raycast.description Patches Tana app by embedding custom CSS directly
# ============================================================================
# CONFIGURATION - Edit these values to customize the CSS injection
# ============================================================================
# Option 1: Use CSS from a URL (set USE_INLINE_CSS=false)
CSS_URL="https://gist.githubusercontent.com/foeken/cd809018e6caf846d174f656bb30109c/raw/313e673744ad85205351ce0d6a32a75d14f27120/tana.css"
# Option 2: Use inline CSS (set USE_INLINE_CSS=true and paste your CSS below)
USE_INLINE_CSS=false
# Paste your CSS here (between the quotes) if using inline CSS:
INLINE_CSS='
/* Example CSS - replace with your own */
body {
font-family: '\''IBM Plex Sans'\'';
-webkit-font-smoothing: subpixel-antialiased;
font-size: 14.5px !important;
}
'
# ============================================================================
# SCRIPT LOGIC - Do not modify below this line unless you know what you're doing
# ============================================================================
TANA_PRELOAD_PATH="/Applications/Tana.app/Contents/Resources/app/build/preload.js"
# Check if Tana app exists
if [ ! -f "$TANA_PRELOAD_PATH" ]; then
echo "Tana app not found"
exit 1
fi
# Check if already patched and handle re-patching
if grep -q "TANA_CUSTOM_CSS_INJECTED" "$TANA_PRELOAD_PATH"; then
# Check if backup exists
if [ ! -f "$TANA_PRELOAD_PATH.backup" ]; then
echo "No backup found - cannot safely update"
exit 1
fi
# Restore from backup first
cp "$TANA_PRELOAD_PATH.backup" "$TANA_PRELOAD_PATH"
fi
# Get CSS content based on configuration
if [ "$USE_INLINE_CSS" = true ]; then
CSS_CONTENT="$INLINE_CSS"
CSS_SOURCE="inline CSS from script"
else
# Download CSS with proper error handling
HTTP_RESPONSE=$(curl -s -w "HTTPSTATUS:%{http_code}" "$CSS_URL")
HTTP_STATUS=$(echo "$HTTP_RESPONSE" | tr -d '\n' | sed -E 's/.*HTTPSTATUS:([0-9]{3})$/\1/')
CSS_CONTENT=$(echo "$HTTP_RESPONSE" | sed -E 's/HTTPSTATUS:[0-9]{3}$//')
# Check for HTTP errors or empty content
if [ "$HTTP_STATUS" -lt 200 ] || [ "$HTTP_STATUS" -ge 300 ] || [ -z "$CSS_CONTENT" ]; then
echo "Failed to download CSS"
exit 1
fi
CSS_SOURCE="$CSS_URL"
fi
# Create a backup (only if one doesn't exist)
if [ ! -f "$TANA_PRELOAD_PATH.backup" ]; then
cp "$TANA_PRELOAD_PATH" "$TANA_PRELOAD_PATH.backup"
fi
# Escape the CSS content for JavaScript string
CSS_ESCAPED=$(echo "$CSS_CONTENT" | sed 's/\\/\\\\/g' | sed "s/'/\\\\'/g" | sed 's/"/\\"/g' | tr '\n' ' ')
# The code to inject with embedded CSS
INJECTION_CODE="
// TANA_CUSTOM_CSS_INJECTED - DO NOT REMOVE THIS MARKER
document.onreadystatechange = async (event) => {
if (document.readyState == \"complete\") {
try {
const css = \`$CSS_ESCAPED\`;
var styleSheet = document.createElement(\"style\");
styleSheet.innerText = css;
document.head.appendChild(styleSheet);
console.log('Tana custom CSS applied successfully');
} catch (err) {
console.error('Failed to apply custom CSS:', err);
}
}
};"
# Add the code to the end of the file
echo "$INJECTION_CODE" >> "$TANA_PRELOAD_PATH"
# Check if Tana is running and quit it
if pgrep -f "Tana" > /dev/null; then
osascript -e 'tell application "Tana" to quit'
sleep 1
fi
# Start Tana again
open -a "Tana"
echo "Custom CSS applied successfully"
/* Create a draggable region at the top of the window */
body::before {
content: '';
position: fixed;
top: 0;
left: 0;
right: 0;
height: 15px;
-webkit-app-region: drag;
z-index: 1000;
pointer-events: none;
}
body {
font-family: 'IBM Plex Sans';
-webkit-font-smoothing: subpixel-antialiased;
font-size: 14.5px !important;
}
/*img.inlineavatar {
margin-right: 0.1em;
}*/
mark {
background-color: hsla(51, 98%, 81%, .69);
}
/* Hide related content if it's a search node that returns no results */
/*
div[class*="WidgetPanel-module_container"]:has(
div[class*="Message-module_subtle"][class*="Message-module_smaller"]
) {
display: none !important;
}*/
/* progress bars */
div[style*="background-color: rgb(76, 175, 80)"] {
background-color: var(--templateColor) !important;
opacity: 0.5;
}
div[style*="background-color: var(--colorUIStroke)"] {
opacity: 0.5;
}
/* Brighten colors of icons when selected in picker to combat for blue background */
div[data-selected] img {
filter: brightness(200%);
}
/* Grayscale and Hide icons in sidebar */
.UnifiedSidebar-module_main__vPzV5 .NodeAsDrilldownElement-module_icon__tpAP0 {
filter: grayscale(100%) brightness(70%);
display: none;
}
/* Reduce colors of dates, icons, and links in checked todos */
.itemdone-checkbox .inlineelement.inlinerefnode, .itemdone-checkbox .inlineelement.inlinerefdate, .itemdone-checkbox a {
filter: grayscale(70%);
}
/* Darken icons on hover (same as text) */
.inlinecontent.hastemplate:hover .inlineavatar{
filter: brightness(70%);
}
/* Quotes and block-quotes */
:has(span[data-tag="quote"]):not(.expandedNodeContent) > .listContentItem,
:has(span[data-tag="block-quote"]):not(.expandedNodeContent) > .listContentItem {
background-color: var(--colorReferenceMentionBackground);
border-left: 5px solid var(--colorUIStroke);
border-left-width: 3px;
border-radius: 3px;
padding: 8px 14px;
}
/* New Zettel */
.NodeAsListElement-module_main__kwj8T .listContentItem:has(span[data-tag="literature-note"]) {
margin-bottom: 3px;
}
.listContentItem:has(span[data-tag="literature-note"]) {
color: #5f2552a1;
font-style: italic;
}
:has(span[data-tag="literature-note"]):not(.expandedNodeContent) > .listContentItem {
background-color: #f4ebf373;
border-left: 5px solid #b2459aa1;
border-left-width: 3px;
border-radius: 3px;
padding: 8px 14px;
}
.isDarkMode :has(span[data-tag="literature-note"]):not(.expandedNodeContent) > .listContentItem {
background-color: #38173087;
color: #c772b4d6;
border-left: 5px solid #722e6382;
}
div[data-panel-content="true"] .listContentItem:has(span[data-tag="missing-zettel"]) .editable {
color: #D78B37 !important;
}
div[data-panel-content="true"] .listContentItem:has(span[data-tag="zettel"]) .editable {
color: #58814F !important;
}
/* Sections */
.listContentItem:has(span[data-tag="highlights-section"]) .editable {
background-color: #F2BD1D !important;
}
.listContentItem:has(span[data-tag="zettel-section"]) .editable {
background-color: #8D6343 !important;
}
.listContentItem:has(span[data-tag="nedap-section"]) .editable {
background-color: #12537A !important;
}
.listContentItem:has(span[data-tag="work-section"]) .editable {
background-color: #12537A !important;
}
.listContentItem:has(span[data-tag="journal-section"]) .editable {
background-color: #73A867 !important;
}
.listContentItem:has(span[data-tag="中文-section"]) .editable {
background-color: #FEA443 !important;
}
.listContentItem:has(span[data-tag="metrics-section"]) .editable {
background-color: #565656 !important;
}
.listContentItem:has(span[data-tag="spotlight-section"]) .editable {
background-color: #FEA443 !important;
}
div[data-tag-name="spotlight-section"] .OutlinerItem-module_typeWrapper__ai0zS {
display: none;
}
.listContentItem:has(span[data-tag="personal-section"]) .editable {
background-color: #1E86C7 !important;
}
.listContentItem:has(span[data-tag="inbox-section-old"]) .editable {
background-color: #D95F69 !important;
}
.listContentItem:has(span[data-tag="literature-notes"]) .editable {
background-color: #8F3B7B !important;
}
.listContentItem:has(span[data-tag="fleeting-notes"]) .editable {
background-color: #DB86C7 !important;
}
.listContentItem:has(span[data-tag="zettel-notes"]) .editable {
background-color: #73A867 !important;
}
.listContentItem:has(span[data-tag="scratchpad-section"]) .editable {
background-color: #565656 !important;
}
.listContentItem:has(span[data-tag="highlights-section"]) .editable,
.listContentItem:has(span[data-tag="zettel-section"]) .editable,
.listContentItem:has(span[data-tag="nedap-section"]) .editable,
.listContentItem:has(span[data-tag="work-section"]) .editable,
.listContentItem:has(span[data-tag="journal-section"]) .editable,
.listContentItem:has(span[data-tag="中文-section"]) .editable,
.listContentItem:has(span[data-tag="spotlight-section"]) .editable,
.listContentItem:has(span[data-tag="personal-section"]) .editable,
.listContentItem:has(span[data-tag="inbox-section-old"]) .editable,
.listContentItem:has(span[data-tag="scratchpad-section"]) .editable,
.listContentItem:has(span[data-tag="metrics-section"]) .editable,
.listContentItem:has(span[data-tag="literature-notes"]) .editable,
.listContentItem:has(span[data-tag="zettel-notes"]) .editable,
.listContentItem:has(span[data-tag="fleeting-notes"]) .editable {
padding: 3px 7px;
line-height: 1.8em;
border-radius: 3px;
color: white;
border: none;
margin-right: 2px;
}
.listContentItem:has(span[data-tag="highlights-section"]) .inlineelement,
.listContentItem:has(span[data-tag="zettel-section"]) .inlineelement,
.listContentItem:has(span[data-tag="personal-section"]) .inlineelement,
.listContentItem:has(span[data-tag="journal-section"]) .inlineelement,
.listContentItem:has(span[data-tag="inbox-section-old"]) .inlineelement,
.listContentItem:has(span[data-tag="scratchpad-section"]) .inlineelement,
.listContentItem:has(span[data-tag="metrics-section"]) .inlineelement,
.listContentItem:has(span[data-tag="中文-section"]) .inlineelement,
.listContentItem:has(span[data-tag="spotlight-section"]) .inlineelement,
.listContentItem:has(span[data-tag="work-section"]) .inlineelement,
.listContentItem:has(span[data-tag="nedap-section"]) .inlineelement {
background: inherit !important;
color: white;
border: none;
}
/* Low opacity tags */
.listContentItem span[data-tag="zettel"],
.listContentItem span[data-tag="missing"],
.listContentItem span[data-tag="highlights-section"],
.listContentItem span[data-tag="zettel-section"],
.listContentItem span[data-tag="personal-section"],
.listContentItem span[data-tag="nedap-section"],
.listContentItem span[data-tag="work-section"],
.listContentItem span[data-tag="journal-section"],
.listContentItem span[data-tag="inbox-section-old"],
.listContentItem span[data-tag="scratchpad-section"],
.listContentItem span[data-tag="中文-section"],
.listContentItem span[data-tag="spotlight-section"],
.listContentItem span[data-tag="metrics-section"],
.listContentItem span[data-tag="literature-notes"],
.listContentItem span[data-tag="zettel-notes"],
.listContentItem span[data-tag="fleeting-notes"] {
opacity: 0.4
}
.listContentItem:hover span[data-tag="zettel"],
.listContentItem:hover span[data-tag="missing"],
.listContentItem:hover span[data-tag="highlights-section"],
.listContentItem:hover span[data-tag="zettel-section"],
.listContentItem:hover span[data-tag="personal-section"],
.listContentItem:hover span[data-tag="nedap-section"],
.listContentItem:hover span[data-tag="work-section"],
.listContentItem:hover span[data-tag="journal-section"],
.listContentItem:hover span[data-tag="inbox-section-old"],
.listContentItem:hover span[data-tag="scratchpad-section"],
.listContentItem:hover span[data-tag="metrics-section"],
.listContentItem:hover span[data-tag="中文-section"],
.listContentItem:hover span[data-tag="spotlight-section"],
.listContentItem:hover span[data-tag="literature-notes"],
.listContentItem:hover span[data-tag="zettel-notes"],
.listContentItem:hover span[data-tag="fleeting-notes"] {
opacity: 1
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment