Showing preview only (794K chars total). Download the full file or copy to clipboard to get everything.
Repository: sindresorhus/sindresorhus.github.com
Branch: main
Commit: 6311d853d37e
Files: 159
Total size: 742.6 KB
Directory structure:
gitextract_c4ya43z6/
├── .editorconfig
├── .gitattributes
├── .github/
│ └── workflows/
│ └── deploy.yml
├── .gitignore
├── AGENTS.md
├── astro.config.js
├── license
├── note-to-self.md
├── package.json
├── public/
│ ├── CNAME
│ ├── apps/
│ │ └── heic-converter/
│ │ └── heic-example.heic
│ ├── feedback/
│ │ └── index.html
│ └── keybase.txt
├── readme.md
├── source/
│ ├── components/
│ │ ├── apps/
│ │ │ ├── AppsByPlatform.astro
│ │ │ ├── AppsCategory.astro
│ │ │ └── AppsList.astro
│ │ ├── blog/
│ │ │ ├── List.astro
│ │ │ ├── ListItem.astro
│ │ │ ├── Pagination.astro
│ │ │ ├── Post.astro
│ │ │ └── Tags.astro
│ │ ├── core/
│ │ │ ├── MetaTags.astro
│ │ │ └── ToggleMenu.astro
│ │ └── widgets/
│ │ ├── Announcement.astro
│ │ ├── Footer.astro
│ │ ├── Header.astro
│ │ ├── HeaderLink.astro
│ │ ├── OverflowMenu.astro
│ │ ├── PressQuotes.astro
│ │ └── RelatedApps.astro
│ ├── config.mjs
│ ├── content/
│ │ ├── apps/
│ │ │ ├── actions.md
│ │ │ ├── ai-actions.md
│ │ │ ├── aiko.md
│ │ │ ├── amazing-ai.md
│ │ │ ├── any-text.md
│ │ │ ├── app-buddy.md
│ │ │ ├── ask-ai.md
│ │ │ ├── battery-indicator.md
│ │ │ ├── black-out.md
│ │ │ ├── blear.md
│ │ │ ├── camera-preview.md
│ │ │ ├── caprine.md
│ │ │ ├── command-x.md
│ │ │ ├── dato.md
│ │ │ ├── day-progress.md
│ │ │ ├── default-browser.md
│ │ │ ├── doodle-draw.md
│ │ │ ├── ds-store-inspector.md
│ │ │ ├── favorites-widget.md
│ │ │ ├── floating-clock.md
│ │ │ ├── folder-peek.md
│ │ │ ├── gifski.md
│ │ │ ├── googly-eyes.md
│ │ │ ├── heic-converter.md
│ │ │ ├── hyperduck.md
│ │ │ ├── icon-preview.md
│ │ │ ├── imago.md
│ │ │ ├── jiffy.md
│ │ │ ├── lungo.md
│ │ │ ├── memo-widget.md
│ │ │ ├── menu-bar-calendar.md
│ │ │ ├── menu-bar-spacing.md
│ │ │ ├── menu-drop.md
│ │ │ ├── one-task.md
│ │ │ ├── one-thing.md
│ │ │ ├── online-check.md
│ │ │ ├── pandan.md
│ │ │ ├── pasteboard-viewer.md
│ │ │ ├── photo-widget.md
│ │ │ ├── plain-text-editor.md
│ │ │ ├── plash.md
│ │ │ ├── pure-paste.md
│ │ │ ├── quick-launch.md
│ │ │ ├── quickgpt.md
│ │ │ ├── randa.md
│ │ │ ├── recordia.md
│ │ │ ├── scratchpad.md
│ │ │ ├── second-clock.md
│ │ │ ├── shareful.md
│ │ │ ├── short-run.md
│ │ │ ├── shortcutie.md
│ │ │ ├── simple-color-palette.md
│ │ │ ├── spaced.md
│ │ │ ├── speediness.md
│ │ │ ├── supercharge.md
│ │ │ ├── system-color-picker.md
│ │ │ ├── text-lens.md
│ │ │ ├── today.md
│ │ │ ├── touch-bar-simulator.md
│ │ │ ├── utc-time.md
│ │ │ ├── velja.md
│ │ │ ├── week-number.md
│ │ │ └── zone-bar.md
│ │ └── blog/
│ │ ├── empathy-in-open-source.md
│ │ ├── goodbye-nodejs-buffer.md
│ │ ├── issue-bumping.md
│ │ ├── micro-benchmark-fallacy.md
│ │ ├── shortcutie-setapp.md
│ │ └── small-focused-modules.md
│ ├── content.config.ts
│ ├── data/
│ │ └── apps-extra.json
│ ├── env.d.ts
│ ├── layouts/
│ │ ├── BaseLayout.astro
│ │ ├── BlogLayout.astro
│ │ ├── MarkdownLayout.astro
│ │ ├── PageLayout.astro
│ │ └── SimplePageLayout.astro
│ ├── pages/
│ │ ├── 404.astro
│ │ ├── [...apps]/
│ │ │ ├── [slug]/
│ │ │ │ ├── privacy-policy.astro
│ │ │ │ ├── release-notes.astro
│ │ │ │ └── rss.xml.js
│ │ │ └── [slug].astro
│ │ ├── [...blog]/
│ │ │ ├── [...page].astro
│ │ │ ├── [slug].astro
│ │ │ └── _[tag]/
│ │ │ └── [...page].astro
│ │ ├── _apps-extra.astro
│ │ ├── _apps-heatmap.astro
│ │ ├── about.md
│ │ ├── apps/
│ │ │ ├── affiliates.md
│ │ │ ├── archived.astro
│ │ │ ├── discounts.md
│ │ │ ├── faq.md
│ │ │ ├── free.astro
│ │ │ ├── ios.astro
│ │ │ ├── macos.astro
│ │ │ ├── menu-bar.astro
│ │ │ ├── older-versions.astro
│ │ │ ├── paid.astro
│ │ │ ├── random.astro
│ │ │ ├── setapp.astro
│ │ │ ├── shortcuts.astro
│ │ │ ├── terms.md
│ │ │ ├── visionos.astro
│ │ │ └── watchos.astro
│ │ ├── apps.astro
│ │ ├── contact.astro
│ │ ├── donate.md
│ │ ├── feedback.astro
│ │ ├── feeds.astro
│ │ ├── index.astro
│ │ ├── og/
│ │ │ └── [slug].png.js
│ │ ├── repos.md
│ │ ├── rss-apps.xml.js
│ │ ├── rss-repos.xml.js
│ │ ├── rss.xml.js
│ │ ├── supporters.md
│ │ └── tiny-apps.md
│ └── utils/
│ ├── apps.js
│ ├── permalinks.js
│ ├── posts.js
│ ├── rehype-kbd-separator.js
│ ├── remark-heading-meta.js
│ ├── remark-inject-feedback-faq.js
│ ├── remark-inject-feedback-faq.test.js
│ └── utils.js
├── styles/
│ └── global.css
└── tsconfig.json
================================================
FILE CONTENTS
================================================
================================================
FILE: .editorconfig
================================================
root = true
[*]
indent_style = tab
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
[*.yml]
indent_style = space
indent_size = 2
================================================
FILE: .gitattributes
================================================
* text=auto eol=lf
================================================
FILE: .github/workflows/deploy.yml
================================================
name: Deploy
on:
push:
branches:
- main
workflow_dispatch:
schedule:
- cron: '0 0 * * *' # Runs every night at midnight UTC
jobs:
build:
permissions:
contents: read
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: withastro/action@v5
deploy:
needs: build
permissions:
pages: write
id-token: write
runs-on: ubuntu-latest
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
steps:
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v4
================================================
FILE: .gitignore
================================================
node_modules
yarn.lock
/dist
/.output
*.sublime-project
*.sublime-workspace
.astro
.cache
================================================
FILE: AGENTS.md
================================================
# Codebase Notes
## FAQ Suggestions on /feedback
The feedback page shows relevant FAQ links as the user types their message.
### Data sources
- **General FAQs** — a curated subset of `source/pages/apps/faq.md` headings, filtered by slug via `feedbackFaqSlugs` in `feedback.astro`.
- **App-specific FAQs** — all FAQ headings from the selected app's markdown file (via `?product=` URL param), passed through `faqHeadings` in `apps.js`.
### Heading metadata (`<!-- @namespace.attribute value -->`)
Any markdown heading with a `{#id}` can be annotated with directives on the lines immediately below:
```md
### The app does not show up in the menu bar {#app-not-showing-in-menu-bar}
<!-- @faq.keywords launching launch start open opening -->
<!-- @faq.platforms macOS -->
```
- Parsed by the `remarkHeadingMeta` plugin (`source/utils/remark-heading-meta.js`), which runs after `remarkCustomHeaderId` so heading IDs are already set.
- Injected into `file.data.astro.frontmatter.headingMeta` and accessed in `feedback.astro` as `faqMd.frontmatter.headingMeta`.
- Values are always arrays (split on whitespace).
- Multiple directives per heading work by looking back past consecutive `<!-- @... -->` nodes to find the owning heading.
- The `@faq.` namespace is consumed by the feedback page. Other namespaces can be added for future uses.
**`@faq.keywords`** — extra words that make a FAQ matchable by queries that don't use the same words as the heading text.
**`@faq.platforms`** — restricts the FAQ to apps that support at least one of these platforms. FAQs without this annotation are shown for all apps.
### Matching algorithm (`feedback.astro`, second `<script>` block)
1. **Tokenize** — lowercase, strip apostrophes, extract words ≥4 chars, filter stopwords.
2. **Score** — TF-IDF: each query word that matches a FAQ word (exact or prefix) adds `log((n+1)/(df+1))` to the FAQ's score. Rare words score higher.
3. **FAQ words** include the question text + `@faq.keywords`, expanded with synonyms.
4. **minMatches** — requires ≥2 query words to match when ≥2 meaningful ("known") query words exist, preventing single generic terms from matching everything. Pinned FAQs bypass this and only need 1 match.
5. **Pinned FAQs** (`pinnedUrls`) always sort to the top when matched.
6. **App-specific FAQs** sort above general FAQs.
7. **Deduplication** — general FAQs with ≥0.6 Jaccard similarity to an app-specific result are removed.
### Synonyms
**General synonyms** (e.g. `icloud` ↔ `sync`) live in the `SYNONYMS` map in `feedback.astro`. They expand FAQ words so cross-term matches work both ways.
Do **not** use `@faq.keywords` for synonyms — keywords are for *additional match terms specific to one FAQ*. Synonyms express a relationship between two concepts that applies across all FAQs mentioning either term.
### Why a FAQ didn't show for a given email
Common causes: (a) missing keywords/synonyms so the FAQ doesn't match enough query words, (b) weak app-specific FAQs crowd it out of the top-4 (app-specific FAQs rank above general ones at equal matchCount), (c) stopwords eat key terms (e.g. "back up" → "back" is a stopword, "up" is <4 chars). Fix by adding `@faq.keywords` to the FAQ or synonyms to the `SYNONYMS` map.
================================================
FILE: astro.config.js
================================================
import process from 'node:process';
import fs from 'node:fs';
import https from 'node:https';
import tls from 'node:tls';
import path from 'node:path';
import {fileURLToPath} from 'node:url';
import {defineConfig} from 'astro/config';
import sitemap from '@astrojs/sitemap';
import remarkCustomHeaderId from 'remark-custom-header-id';
import remarkGitHubAlerts from 'remark-github-blockquote-alert';
import tailwindcss from '@tailwindcss/vite';
import {icons as tablerIconData} from '@iconify-json/tabler';
import rehypeRaw from 'rehype-raw';
import remarkHeadingMeta from './source/utils/remark-heading-meta.js';
import remarkInjectFeedbackFaq from './source/utils/remark-inject-feedback-faq.js';
import rehypeKbdSeparator from './source/utils/rehype-kbd-separator.js';
/// import rehypeAutolinkHeadings from 'rehype-autolink-headings';
import {SITE} from './source/config.mjs';
// Patch fetch to serve Iconify icons from local @iconify-json packages, enabling offline dev.
const originalFetch = globalThis.fetch;
globalThis.fetch = async (input, init) => {
let url;
if (typeof input === 'string') {
url = input;
} else if (input instanceof URL) {
url = input.href;
} else {
url = input.url;
}
const match = url.match(/^https:\/\/api\.iconify\.design\/(\w+)\.json/);
if (match) {
const localPacks = {tabler: tablerIconData};
const pack = localPacks[match[1]];
if (pack) {
return new Response(JSON.stringify(pack), {
headers: {'Content-Type': 'application/json'},
});
}
}
return originalFetch(input, init);
};
/*
Work around Socket Firewall (sfw) breaking fetch() during builds.
sfw sets NODE_EXTRA_CA_CERTS for its MITM proxy CA, but Node's built-in
fetch (undici) does not pick it up when the env var is set after startup.
We fall back to node:https (which supports explicit CA) for HTTPS requests.
*/
{
const certPath = process.env.NODE_EXTRA_CA_CERTS;
const cert = certPath && fs.existsSync(certPath)
? fs.readFileSync(certPath, 'utf8')
: undefined;
if (cert) {
const ca = [...tls.rootCertificates, cert];
const previousFetch = globalThis.fetch;
globalThis.fetch = async (input, init) => {
const url = typeof input === 'string' ? input : (input instanceof URL ? input.href : input.url);
if (!url?.startsWith('https://')) {
return previousFetch(input, init);
}
return new Promise((resolve, reject) => {
const parsedUrl = new URL(url);
const agent = new https.Agent({ca});
const request = https.get({
hostname: parsedUrl.hostname,
path: parsedUrl.pathname + parsedUrl.search,
headers: {
'User-Agent': 'node',
...Object.fromEntries(new Headers(init?.headers).entries()),
},
agent,
}, response => {
const chunks = [];
response.on('data', chunk => chunks.push(chunk));
response.on('end', () => {
resolve(new Response(Buffer.concat(chunks).toString(), {
status: response.statusCode,
headers: response.headers,
}));
agent.destroy();
});
});
request.on('error', reject);
});
};
}
}
const __dirname = path.dirname(fileURLToPath(import.meta.url));
// https://astro.build/config
export default defineConfig({
site: SITE.origin,
srcDir: './source',
output: 'static',
trailingSlash: 'never',
build: {
format: 'file',
},
redirects: {
'/thanks': '/supporters',
'/lock-screen-one': '/any-text',
},
integrations: [
sitemap(),
],
markdown: {
remarkPlugins: [
remarkCustomHeaderId,
remarkGitHubAlerts,
remarkHeadingMeta,
remarkInjectFeedbackFaq,
],
rehypePlugins: [
// Astro runs rehype-raw after user plugins, so inline HTML stays as opaque `raw` nodes when our plugins run. Running it first converts them to proper hast elements.
rehypeRaw,
rehypeKbdSeparator,
// TODO
// rehypeHeadingIds,
// [rehypeAutolinkHeadings, {behavior: 'wrap'}],
],
},
vite: {
resolve: {
alias: {
'~': path.resolve(__dirname, './source'),
},
},
plugins: [
tailwindcss(),
],
},
});
================================================
FILE: license
================================================
MIT License
Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (https://sindresorhus.com)
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.
================================================
FILE: note-to-self.md
================================================
# Note to self
- Use `.not-prose` to avoid prose styles.
================================================
FILE: package.json
================================================
{
"private": true,
"type": "module",
"engines": {
"node": ">=22"
},
"scripts": {
"dev": "astro dev",
"start": "astro dev --open",
"build": "xo && astro build",
"preview": "astro preview",
"test": "xo && astro build"
},
"devDependencies": {
"@astrojs/rss": "^4.0.18",
"@astrojs/sitemap": "^3.7.2",
"@astropub/md": "^1.0.0",
"@fontsource/inter": "^5.2.8",
"@iconify-json/tabler": "^1.2.33",
"@resvg/resvg-js": "^2.6.2",
"@tailwindcss/forms": "^0.5.11",
"@tailwindcss/typography": "^0.5.19",
"@tailwindcss/vite": "^4.2.2",
"@typescript-eslint/parser": "^8.58.1",
"astro": "^6.1.5",
"astro-iconify": "^1.3.1",
"astro-seo": "^1.1.0",
"eslint-plugin-astro": "^1.7.0",
"ky": "^1.14.3",
"limax": "^4.2.3",
"markdown-it": "^14.1.1",
"reading-time": "^1.5.0",
"rehype-autolink-headings": "^7.1.0",
"rehype-slug": "^6.0.0",
"remark-custom-header-id": "^1.0.0",
"remark-github-blockquote-alert": "^2.1.0",
"sanitize-html": "^2.17.2",
"satori": "^0.26.0",
"tailwindcss": "^4.2.2",
"typescript": "^5.9.3",
"xo": "^0.60.0"
},
"xo": {
"envs": [
"es2021",
"node",
"browser"
],
"globals": [
"Astro",
"Fragment"
],
"extensions": [
"astro"
],
"ignores": [
"source/content.config.ts"
],
"overrides": [
{
"files": [
"**/*.astro"
],
"parser": "astro-eslint-parser",
"parserOptions": {
"parser": "@typescript-eslint/parser"
},
"extraFileExtensions": [
".astro"
],
"rules": {
"indent": "off"
}
}
],
"rules": {
"unicorn/filename-case": "off",
"unicorn/text-encoding-identifier-case": "off",
"n/file-extension-in-import": "off",
"operator-linebreak": "off",
"jsx-quotes": [
"error",
"prefer-double"
],
"unicorn/prevent-abbreviations": "off"
}
}
}
================================================
FILE: public/CNAME
================================================
sindresorhus.com
================================================
FILE: public/feedback/index.html
================================================
<!doctype html>
<html lang="en">
<meta charset="utf-8">
<title>Redirecting…</title>
<link rel="canonical" href="https://sindresorhus.com/feedback">
<meta http-equiv="refresh" content="1; url=https://sindresorhus.com/feedback">
<script type="module" is:inline>
let url = 'https://sindresorhus.com/feedback';
if (location.search) {
url = url.replace(/($|#)/, `${location.search}$1`);
}
if (location.hash) {
url += location.hash;
}
location = url;
</script>
<h2>Redirecting…</h2>
</html>
================================================
FILE: public/keybase.txt
================================================
==================================================================
https://keybase.io/sindresorhus
--------------------------------------------------------------------
I hereby claim:
* I am an admin of https://sindresorhus.com
* I am sindresorhus (https://keybase.io/sindresorhus) on keybase.
* I have a public key with fingerprint 9167 E91F 3DA4 65D0 020A 48B3 5A35 FFDB 8B07 983A
To do so, I am signing this object:
{
"body": {
"key": {
"eldest_kid": "01203b7530668e317929a6e3448ee9caaa430129790178d70b438441c367513baf7f0a",
"fingerprint": "9167e91f3da465d0020a48b35a35ffdb8b07983a",
"host": "keybase.io",
"key_id": "5a35ffdb8b07983a",
"kid": "0101cb611ee03ce62c90d7bb7e8ee3aba2c539d8bbb07c3be2ce6e01371539d94ba50a",
"uid": "b6eaadc02135408a3c296cd49dabdb19",
"username": "sindresorhus"
},
"service": {
"hostname": "sindresorhus.com",
"protocol": "https:"
},
"type": "web_service_binding",
"version": 1
},
"ctime": 1531853124,
"expire_in": 157680000,
"prev": "cbab6bb516e46064f0efe0c1c7d5463fa994de8e6a4afb91b4bcb9359bd3ba0c",
"seqno": 36,
"tag": "signature"
}
which yields the signature:
-----BEGIN PGP MESSAGE-----
Version: Keybase OpenPGP v2.0.77
Comment: https://keybase.io/crypto
yMNsAnicbZJ9UFRVGMZBSSZSWDG+EpSu6Cy4LPf7Y1GQ0hTKWHFIg5LOuffc5cay
u9xdBNxBJUNhGKdFA8SvbIqhCWIAKRVzcCUC8w8aGcQRHZtpMoIYK4micaJ7mfzP
O3Pmzjnn9zzned9zvlm2OCAkMI+ZH68LPmEJvOE/VxqQ/7qw2YtBp1SBWbxYEVr4
IbuE3J6CIkXCLBhOkDgFOYbCWZZHFMEJpABYRNE0j5AgAgBoSmMETsAJjpc4HNIU
T9OESLEcQ1AQyJyMA8yEyYrDhlSXqjg8mq1AsBwSCJmSAM0yEo6TOKB5SDGAYmRZ
gjzEOYGndGGh060rtHAQuJFZcWpr2qRgId5T+Ce5cUKELEEghFMiYklRwCUOQg5p
uSkAASkylCDxEGpKkYKI1CCEExRH6OsCDQGzkLt0wQ6yCABJxEmCYmicB5RICqwo
0YIEoAQJQQfdSHWAYqTRbsUhqcjtVAtL3VilCdN29ioi0purV/MUyiw6izUPl+r0
OEWnXdst9Hhcbouu9lS4dLwMwYL/jQqgJtX6qSn2ItWtOB2YhdBI0aPozloFBK8N
kjZhqNylqKhA0QmGY3lc+/Rz0F7NUoQAshAyBItoFmdpGUcywkVC5CSGZikZCAIt
aQ1jAQ1kKBCQhiIUKEaAknazuIjppZU4nJiFYrWcwLZQlc0BPKUqwiqv+d8KCggM
CVjyzCL9oQWEPGt48vzie8LmpY4101Zy++KDOcEZvz5aYjGM2Dqq/lZawSZr+I8P
bpTtiZ6B6OCZ818cWZM/dCL1Zr/5UvrLoWil4jky8XOSzPpPN6Nbq9jMt81539lW
rx987/j7xueL1p3xZoXtjF8qfdyWMnw9bqIv+Y/wpoenZpu8h3yXbhkH2lef9P0b
d2/QcMUSkxiyrS2hqKknMvqjVNwfMZ7cFttRs3yopPyN/A3xh1MeG3/rqp28P7Lr
+zvNuy7kTbb3Vg7nSclbU+aX1fXP7a/OPPtm2Yah2vqdppXW1yLGZgZc9vrWtUP2
TZ2+qajPT1293EkyQcHTL228G2/8oKs4ua67y1n9SvaOlplu3+TEh5fpfdMJW1TY
lWOYrq3/U+arIrvmvvUz1XuMkSH/GKaaY7q3egdfqPQ2nLQb73qnGo29ab907r9w
/dWkvot/GRMGjmaUFNp9lUGPsar8hFHLufSvR6+EZVtvm2rwsZaLG1vLY9M7D3z2
Se9Pjf27VwTdizifRNV3b5M9xHOJPR2+tT80PJqLbZhEL6aOC6ov851jMccP3FzX
sSM3bjBlhTxWs6qt80vvV9l9o/TmLN6fmzJiMtfVDvtvVxQ++DQ6YzZ30btC/pbT
zFUyy3E4iW85GtUaM2sduhM+MxI18vv60GNR+2wO7po1r3F5Wm+a0WzYfp+Te0Md
D5e2z+8+m5NI/Adyjbj7
=h6oE
-----END PGP MESSAGE-----
And finally, I am proving ownership of this host by posting or
appending to this document.
View my publicly-auditable identity here: https://keybase.io/sindresorhus
==================================================================
================================================
FILE: readme.md
================================================
# [sindresorhus.com](https://sindresorhus.com)
> Personal website of Sindre Sorhus
*The website targets the latest version of Chrome, Safari, and Firefox.*
================================================
FILE: source/components/apps/AppsByPlatform.astro
================================================
---
// Group and render apps by platform with subsections.
const {apps = []} = Astro.props;
// Default order for platform sections (Apple platforms only).
const platformOrder = ['macOS', 'iOS', 'watchOS', 'tvOS', 'visionOS'];
const orderIndex = platform => {
const index = platformOrder.indexOf(platform);
return index === -1 ? Number.MAX_SAFE_INTEGER : index;
};
const platforms = [...new Set(apps.flatMap(app => app.platforms))]
.filter(Boolean)
.sort((a, b) => orderIndex(a) - orderIndex(b));
---
{platforms.map(platform => (
<section key={platform}>
<h2 id={platform.toLowerCase()}>{platform}</h2>
<ul>
{apps.filter(app => app.platforms?.includes(platform)).map(app => (
<li key={app.title}><a href={app.url}>{app.title}</a> — {app.subtitle}</li>
))}
</ul>
</section>
))}
================================================
FILE: source/components/apps/AppsCategory.astro
================================================
---
import {markdown} from '@astropub/md';
import {SITE} from '~/config.mjs';
import Layout from '~/layouts/SimplePageLayout.astro';
import {fetchApps} from '~/utils/apps.js';
import AppsList from '~/components/apps/AppsList.astro';
import AppsByPlatform from '~/components/apps/AppsByPlatform.astro';
const {
title,
description,
metaTitle,
filter,
slugs = [],
includeArchived = false,
groupByPlatform = false,
} = Astro.props;
const allApps = await fetchApps({includeArchived});
let selected = allApps;
if (Array.isArray(slugs) && slugs.length > 0) {
selected = slugs
.map(slug => allApps.find(app => app.slug === slug))
.filter(Boolean);
} else if (typeof filter === 'function') {
selected = allApps.filter(app => filter(app));
}
const meta = {
title: metaTitle ?? `${title} — ${SITE.name}`,
};
let descriptionHtml;
if (description) {
descriptionHtml = await markdown(description);
}
const hasDescriptionSlot = Astro.slots?.has?.('description');
---
<Layout {meta}>
<h1>{title}</h1>
{/*
Use either `description` (Markdown string) or the `description` slot for custom markup:
<AppsCategory
title="Example"
description="This supports **Markdown** links, lists, etc."
/>
Or with slot:
<AppsCategory title="Example">
<Fragment slot="description">
Custom <strong>HTML</strong> with links, components, etc.
</Fragment>
</AppsCategory>
*/}
{hasDescriptionSlot ? (
<slot name="description" />
) : (
descriptionHtml && <div set:html={descriptionHtml} />
)}
{groupByPlatform ? (
<AppsByPlatform apps={selected} />
) : (
<AppsList apps={selected} />
)}
<slot name="footer" />
</Layout>
================================================
FILE: source/components/apps/AppsList.astro
================================================
---
// Renders a simple list of apps as links with subtitles.
const {apps = []} = Astro.props;
---
<ul>
{apps.map(app => (
<li key={app.title}><a href={app.url}>{app.title}</a> — {app.subtitle}</li>
))}
{apps.length === 0 && <li>No apps found.</li>}
</ul>
================================================
FILE: source/components/blog/List.astro
================================================
---
import Item from '~/components/blog/ListItem.astro';
const {posts} = Astro.props;
---
<ul>
{
posts.map(post => (
<li class="mb-10 md:mb-16">
<Item post={post}/>
</li>
))
}
</ul>
================================================
FILE: source/components/blog/ListItem.astro
================================================
---
/// import PostTags from '~/components/blog/Tags.astro';
import {getFormattedDate} from '~/utils/utils.js';
const {post} = Astro.props;
const readingTimeText = post.isRedirect ? '' : ` — ${post.readingTime} min read`;
---
<article class="max-w-md mx-auto md:max-w-none">
<div>
<header>
<h2 class="text-3xl sm:text-4xl font-bold leading-snug mb-2 font-heading">
<a
class="hover:underline hover:underline-offset-4 hover:decoration-3"
href={post.url}
>
{post.title}
</a>
</h2>
</header>
<p class="text-lg sm:text-xl grow mt-2 opacity-80">
{post.description}
</p>
<footer class="mt-4">
<div>
<span class="text-gray-500 dark:text-slate-400">
<time datetime={post.pubDate}>{getFormattedDate(post.pubDate)}</time>{readingTimeText}
</span>
</div>
<!-- <div class="mt-4">
<PostTags tags={post.tags} />
</div> -->
</footer>
</div>
</article>
<style is:inline>
/* Workaround to not add hover underline to the external link symbol */
article h2 a:hover {
box-shadow: inset 0 -4px 0 0 currentColor;
text-decoration: none !important;
}
article h2 a[href^="https://"]:not([href^="https://sindresorhus.com"])::after {
content: ' ⤤';
opacity: 0.6;
}
</style>
================================================
FILE: source/components/blog/Pagination.astro
================================================
---
import {Icon} from 'astro-iconify';
const {
prevUrl,
nextUrl,
prevText: previousText = 'Newer posts',
nextText = 'Older posts',
} = Astro.props;
---
{
(prevUrl || nextUrl) && (
<div class="container flex">
<div class="flex flex-row mx-auto container justify-between">
<a
href={prevUrl}
class={`btn px-2 font-medium text-gray-600 hover:text-gray-900 dark:text-gray-400 dark:hover:text-white shadow-none mr-2
${prevUrl ? '' : 'invisible'}`}
>
<div class="flex flex-row align-middle">
<Icon name="tabler:arrow-left" class="w-6 h-6" />
<p class="ml-2">{previousText}</p>
</div>
</a>
<a
href={nextUrl}
class={`btn px-2 font-medium text-gray-600 hover:text-gray-900 dark:text-gray-400 dark:hover:text-white shadow-none ${
nextUrl ? '' : 'invisible'
}`}
>
<div class="flex flex-row align-middle">
<span class="mr-2">{nextText}</span>
<Icon name="tabler:arrow-right" class="w-6 h-6" />
</div>
</a>
</div>
</div>
)
}
================================================
FILE: source/components/blog/Post.astro
================================================
---
/// import PostTags from '~/components/blog/Tags.astro';
import {getFormattedDate} from '~/utils/utils.js';
import {blogProseCSS as proseCSS} from '~/utils/apps.js';
const {post} = Astro.props;
---
<section class="py-8 sm:py-16 lg:py-14 mx-auto">
<article>
<header class="px-6 max-w-3xl mx-auto">
<p class="mb-2 text-sm font-mono tracking-widest opacity-50">
<time datetime={post.pubDate}>{getFormattedDate(post.pubDate)}</time> — {post.readingTime} min read
</p>
<h1
class={`text-5xl lg:text-6xl font-bold leading-tight tracking-tight font-heading text-balance ${post.description ? 'mb-4' : 'mb-3'}`}
>
{/* We could use non-breaking hyphens to keep compound words together, but that risks overflow on narrow screens. */}
{post.title}
</h1>
{post.description &&
<p class="text-xl italic opacity-65 text-pretty">
{post.description}
</p>
}
<hr class="mt-8 mb-0 border-dashed opacity-15"/>
</header>
<div
id="post-container"
class={proseCSS}
>
<post.Content/>
</div>
<!-- <div class="mx-auto px-8 sm:px-6 max-w-3xl mt-8">
<PostTags tags={post.tags} />
</div> -->
</article>
</section>
<style is:inline>
/* If the first element in the blog post is an image, we remove some of its top padding to make the gap from the header to the post body the same as if it had just been text. */
#post-container:has(> p:first-child > img) {
margin-top: -16px;
}
/* Typographic refinements: ligatures, kerning, oldstyle numerals */
#post-container {
font-feature-settings: 'liga' 1, 'kern' 1, 'onum' 1;
text-rendering: optimizeLegibility;
hyphens: auto;
hanging-punctuation: first;
}
/* Prevent orphans in prose paragraphs */
#post-container p {
text-wrap: pretty;
}
</style>
================================================
FILE: source/components/blog/Tags.astro
================================================
---
import {getPermalink} from '~/utils/permalinks.js';
const {
tags,
class: className = 'text-sm',
} = Astro.props;
---
{
tags && Array.isArray(tags) && (
<ul class={className}>
{tags.map(tag => (
<li class="bg-gray-100 dark:bg-slate-700 inline-block mr-2 mb-2 py-0.5 px-2">
<a href={getPermalink(tag, 'tag')}>{tag}</a>
</li>
))}
</ul>
)
}
================================================
FILE: source/components/core/MetaTags.astro
================================================
---
/// import {ClientRouter} from 'astro:transitions';
import {SEO} from 'astro-seo';
import {SITE} from '~/config.mjs';
import {cleanPathname} from '~/utils/utils.js';
const {
title = SITE.name,
description = '',
image: _image,
imageAlt,
noindex = false,
nofollow = false,
ogTitle = title,
ogType = 'website',
appStoreId,
favicon,
rssFeeds = [],
articleMeta,
} = Astro.props;
const resolvedImageAlt = imageAlt ?? ogTitle ?? title;
const image = _image && new URL(_image, Astro.site);
const canonicalURL = new URL(`/${cleanPathname(Astro.url.pathname)}`, Astro.site);
---
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="author" content="Sindre Sorhus">
<meta name="twitter:site" content="@sindresorhus">
<meta name="twitter:creator" content="@sindresorhus">
<meta name="twitter:description" content={description}>
<meta name="fediverse:creator" content="@sindresorhus@mastodon.social">
<meta name="x-build-time" content={(new Date()).toUTCString()}>
{appStoreId && (
<>
<meta name="apple-itunes-app" content={`app-id=${appStoreId}`}>
<meta name="twitter:card" content="app">
<meta name="twitter:app:id:iphone" content={appStoreId}>
</>
)}
{!appStoreId && image && <meta name="twitter:card" content="summary_large_image">}
{!appStoreId && !image && <meta name="twitter:card" content="summary">}
<link rel="sitemap" href="/sitemap-index.xml">
<link rel="alternate" type="application/rss+xml" title="Sindre Sorhus — Blog" href="/rss.xml">
<link rel="alternate" type="application/rss+xml" title="Sindre Sorhus — New Apps" href="/rss-apps.xml">
<link rel="alternate" type="application/rss+xml" title="Sindre Sorhus — New Repos" href="/rss-repos.xml">
{rssFeeds.map(feed => (
<link rel="alternate" type="application/rss+xml" title={feed.title} href={feed.href}>
))}
<link rel="icon" href={favicon ?? 'data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><text y=%22.9em%22 font-size=%2290%22>🦄</text></svg>'}>
<script async src="https://gc.zgo.at/count.js" data-goatcounter="https://sindresorhus.goatcounter.com/count"></script>
<!-- <ClientRouter/> -->
<SEO
title={title}
description={description}
canonical={canonicalURL.toString()}
noindex={noindex}
nofollow={nofollow}
openGraph={image ? {
basic: {
title: ogTitle,
type: ogType,
image: image.toString(),
url: canonicalURL.toString(),
},
optional: {
description,
locale: 'en_US',
siteName: SITE.name,
},
image: {
alt: resolvedImageAlt,
width: 1200,
height: 630,
},
...(articleMeta && {article: articleMeta}),
} : undefined}
extend={image ? undefined : {
meta: [
{property: 'og:title', content: ogTitle},
{property: 'og:type', content: ogType},
{property: 'og:url', content: canonicalURL.toString()},
{property: 'og:description', content: description},
{property: 'og:locale', content: 'en_US'},
{property: 'og:site_name', content: SITE.name},
...(articleMeta?.publishedTime ? [{property: 'article:published_time', content: articleMeta.publishedTime}] : []),
...(articleMeta?.authors?.map(author => ({property: 'article:author', content: author})) ?? []),
...(articleMeta?.tags?.map(tag => ({property: 'article:tag', content: tag})) ?? []),
],
}}
/>
================================================
FILE: source/components/core/ToggleMenu.astro
================================================
<label for="menu-toggle" class="ml-1.5 text-gray-500 dark:text-gray-400 hover:bg-gray-100 dark:hover:bg-gray-800 focus:outline-hidden focus:ring-4 focus:ring-gray-200 dark:focus:ring-gray-700 rounded-lg text-sm p-2.5 inline-flex items-center transition md:hidden">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="w-6 h-6" aria-hidden="true">
<path stroke="none" d="M0 0h24v24H0z" fill="none"/>
<path d="M4 8l16 0" />
<path d="M4 16l16 0" />
</svg>
</label>
================================================
FILE: source/components/widgets/Announcement.astro
================================================
---
import {Icon} from 'astro-iconify';
import MarkdownIt from 'markdown-it';
const {text, url, urlText = 'Learn more'} = Astro.props;
const md = new MarkdownIt({html: true, linkify: true});
const renderedText = md.renderInline(text);
---
<aside class="flex justify-center px-6 -mt-8 mb-32">
<div class="flex flex-col sm:flex-row items-center gap-4 px-5 py-4 rounded-2xl bg-gradient-to-br from-primary-100/50 via-secondary-50/40 to-primary-50/50 dark:from-primary-900/25 dark:via-secondary-900/20 dark:to-primary-950/25 border border-primary-200/40 dark:border-primary-700/30 shadow-sm text-center sm:text-left">
<span class="hidden sm:flex items-center justify-center w-8 h-8 rounded-full bg-gradient-to-br from-primary-500 to-secondary-500 text-white shadow-sm shrink-0">
<Icon name="tabler:sparkles" class="w-4 h-4"/>
</span>
<p class="text-[15px] sm:text-base font-medium text-gray-700 dark:text-gray-200 [&_a]:underline [&_a]:underline-offset-2 [&_a]:text-primary-600 dark:[&_a]:text-primary-400 [&_strong]:font-semibold [&_code]:bg-gray-200 dark:[&_code]:bg-gray-700 [&_code]:px-1 [&_code]:rounded" set:html={renderedText}/>
{url && (
<a
href={url}
class="announcement-button shrink-0 inline-flex items-center gap-1.5 px-4 py-1.5 text-sm font-semibold text-white bg-gradient-to-r from-primary-600 to-secondary-600 rounded-full shadow-sm"
>
<span>{urlText}</span>
<Icon name="tabler:arrow-right" class="w-4 h-4 arrow"/>
</a>
)}
</div>
</aside>
<style>
.announcement-button {
transition: box-shadow 0.2s, filter 0.2s;
}
.announcement-button:hover {
box-shadow: 0 4px 16px -2px rgba(var(--color-primary-500-rgb, 99, 102, 241), 0.4);
filter: brightness(1.1);
}
.announcement-button .arrow {
transition: transform 0.2s;
}
.announcement-button:hover .arrow {
transform: translateX(2px);
}
</style>
================================================
FILE: source/components/widgets/Footer.astro
================================================
---
import {Icon} from 'astro-iconify';
import {iconLinkCSS} from '~/utils/utils.js';
---
<footer class="border-t border-gray-200 dark:border-slate-800" data-nosnippet>
<div class="max-w-6xl mx-auto px-4 sm:px-6">
<div class="md:flex md:items-center md:justify-between py-6 md:py-8">
<ul class="justify-center flex mb-4 md:order-1 -ml-2 md:ml-4 md:mb-0">
<li>
<a
href="https://x.com/sindresorhus"
rel="me"
aria-label="X (Twitter)"
class={iconLinkCSS}
>
<Icon name="tabler:brand-x" class="w-5 h-5"/>
</a>
</li>
<li>
<a
href="https://mastodon.social/@sindresorhus"
rel="me"
aria-label="Mastodon"
class={iconLinkCSS}
>
<Icon name="tabler:brand-mastodon" class="w-5 h-5"/>
</a>
</li>
<li>
<a
href="https://bsky.app/profile/sindresorhus.com"
rel="me"
aria-label="Bluesky"
class={iconLinkCSS}
>
<Icon name="tabler:brand-bluesky" class="w-5 h-5"/>
</a>
</li>
<li>
<a
href="https://instagram.com/sindresorhus"
rel="me"
aria-label="Instagram"
class={iconLinkCSS}
>
<Icon name="tabler:brand-instagram" class="w-5 h-5"/>
</a>
</li>
<li>
<a
href="https://unsplash.com/@sindresorhus"
rel="me"
aria-label="Unsplash"
class={iconLinkCSS}
>
<Icon name="tabler:brand-unsplash" class="w-5 h-5"/>
</a>
</li>
<li>
<a
class={iconLinkCSS}
aria-label="GitHub"
href="https://github.com/sindresorhus"
>
<Icon name="tabler:brand-github" class="w-5 h-5"/>
</a>
</li>
</ul>
<div class="hidden md:inline text-xs text-gray-700 mr-4 dark:text-slate-400">
<q>The people who are crazy enough to think they can change the world are the ones who do</q>
</div>
</div>
</div>
</footer>
================================================
FILE: source/components/widgets/Header.astro
================================================
---
import {Icon} from 'astro-iconify';
import HeaderLink from './HeaderLink.astro';
import ToggleMenu from '~/components/core/ToggleMenu.astro';
import {cleanPathname, iconLinkCSS} from '~/utils/utils.js';
const {isAppPage = false} = Astro.props;
const currentPath = cleanPathname(Astro.url.pathname);
---
<style is:inline>
html {
scroll-padding-top: 80px; /* The header has 72px height and we add some padding */
}
</style>
<header id="site-header" data-nosnippet class="sticky top-0 z-40 flex-none mx-auto w-full bg-white md:bg-white/90 dark:bg-slate-950 dark:md:bg-slate-950/90 md:backdrop-blur-md border-b dark:border-b-0">
<div id="site-nav-content" class="py-3 px-3 mx-auto w-full md:flex md:justify-between max-w-6xl md:px-4">
<div class="flex justify-between">
<a class="flex items-center" href="/">
<span class="self-center ml-2 text-2xl font-extrabold text-gray-900 whitespace-nowrap dark:text-white">
{currentPath === ''
? '🦄'
: 'Sindre Sorhus'
}
</span>
</a>
<div class="flex items-center md:hidden">
<ToggleMenu/>
</div>
</div>
<input id="menu-toggle" type="checkbox" class="peer sr-only md:hidden" aria-label="Toggle menu">
<nav
class="items-start justify-start w-full md:w-auto hidden peer-checked:flex md:flex text-gray-600 dark:text-slate-200 h-screen md:h-auto"
aria-label="Primary navigation"
id="menu"
itemscope
itemtype="https://schema.org/SiteNavigationElement"
>
<ul class="flex flex-col gap-2 pt-8 md:pt-0 md:flex-row md:self-center w-full md:w-auto collapsed text-4xl md:text-base md:gap-0">
<HeaderLink href="/apps">Apps</HeaderLink>
<HeaderLink href="/about">About</HeaderLink>
<HeaderLink href="/blog">Blog</HeaderLink>
<HeaderLink href="/contact" class="md:hidden">Contact</HeaderLink>
{!isAppPage && <li aria-hidden="true" class="hidden md:block h-6 w-px mx-3 self-center rounded-full bg-slate-200/60 dark:bg-slate-600/50"></li>}
{!isAppPage && <HeaderLink href="/donate">Donate</HeaderLink>}
{!isAppPage && <HeaderLink href="/supporters">Supporters</HeaderLink>}
</ul>
<div class="md:self-center flex items-center mb-4 md:mb-0 ml-2">
<div class="hidden items-center md:flex">
<a
href="/feeds"
aria-label="RSS Feeds"
class={iconLinkCSS}
>
<Icon name="tabler:rss" class="w-5 h-5"/>
</a>
<a
href="/contact"
aria-label="Contact"
class={iconLinkCSS}
>
<Icon name="tabler:mail" class="w-5 h-5"/>
</a>
</div>
</div>
</nav>
</div>
</header>
================================================
FILE: source/components/widgets/HeaderLink.astro
================================================
---
import {cleanPathname} from '~/utils/utils.js';
const {href, class: className, ...properties} = Astro.props;
const currentPath = cleanPathname(Astro.url.pathname);
const isActive = currentPath.startsWith(href.replace(/^\//, ''));
const activeClass = 'underline underline-offset-[7px] decoration-[3px] decoration-secondary-500';
const linkClass = `${isActive ? activeClass : ''} font-medium hover:text-gray-900 dark:hover:text-white px-4 py-3 flex items-center transition duration-150 ease-in-out`;
---
<li>
<a href={href} class:list={[className, ...linkClass.split(' ')]} itemprop="url" {...properties}>
<span itemprop="name"><slot/></span>
</a>
</li>
================================================
FILE: source/components/widgets/OverflowMenu.astro
================================================
---
import {Icon} from 'astro-iconify';
export type OverflowItemProps = {
title: string;
url: string;
};
export type OverflowMenuProps = {
overflowItems?: readonly OverflowItemProps[];
iconClassName?: string;
iconSizeClass?: string;
};
const {overflowItems, iconClassName, iconSizeClass = 'w-5 h-5'} = Astro.props;
const iconClass = iconClassName ?? 'text-primary-600 dark:text-primary-400';
---
<div class="relative flex items-center" style="padding-top:2px">
<select
aria-label="Overflow menu"
class="overflow-menu-component absolute inset-0 w-full h-full opacity-0"
style="font-weight: initial; font-family: system-ui;"
>
<option value="" disabled selected></option>
{overflowItems?.map(item => (
<option value={item.url}>{item.title}</option>
))}
<slot />
</select>
<Icon
name="tabler:dots-circle-horizontal"
class={`${iconSizeClass} pointer-events-none ${iconClass}`}
aria-hidden="true"
/>
</div>
<script is:inline>
document.addEventListener('change', event => {
if (event.target?.matches('.overflow-menu-component')) {
const selectedValue = event.target.value;
if (selectedValue) {
event.target.value = ''; // Clear selection
window.location.href = selectedValue;
}
}
});
</script>
================================================
FILE: source/components/widgets/PressQuotes.astro
================================================
---
const {quotes} = Astro.props;
const isOdd = quotes.length % 2 === 1;
---
<aside class="mx-auto px-6 max-w-3xl mt-28 mb-24">
<div class={`grid gap-x-16 gap-y-20 ${quotes.length > 1 ? 'sm:grid-cols-2' : ''}`}>
{quotes.map(({quote, source, url, isStarRating}, index) => (
<blockquote class={`flex flex-col items-center text-center h-full justify-between ${isOdd && index === quotes.length - 1 ? 'sm:col-span-2 sm:max-w-md sm:mx-auto' : ''}`}>
{isStarRating ? (
<div class="flex gap-0.5 mb-4" aria-label="5 out of 5 stars">
{Array.from({length: 5}).map(() => (
<svg class="w-5 h-5 text-[#FF9500]" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
<path d="M9.049 2.927c.3-.921 1.603-.921 1.902 0l1.07 3.292a1 1 0 00.95.69h3.462c.969 0 1.371 1.24.588 1.81l-2.8 2.034a1 1 0 00-.364 1.118l1.07 3.292c.3.921-.755 1.688-1.54 1.118l-2.8-2.034a1 1 0 00-1.175 0l-2.8 2.034c-.784.57-1.838-.197-1.539-1.118l1.07-3.292a1 1 0 00-.364-1.118L2.98 8.72c-.783-.57-.38-1.81.588-1.81h3.461a1 1 0 00.951-.69l1.07-3.292z"/>
</svg>
))}
</div>
) : (
<span class="text-7xl leading-none text-primary-400 dark:text-primary-500 select-none" aria-hidden="true">“</span>
)}
<p class="mt-0 text-lg italic text-gray-600 dark:text-gray-300 leading-relaxed">
{quote}
</p>
<footer class="mt-4 text-sm font-semibold tracking-wide uppercase text-gray-400 dark:text-gray-500">
{url
? <a href={url} class="hover:text-primary-500 transition-colors">{source}</a>
: <span>{source}</span>
}
</footer>
</blockquote>
))}
</div>
</aside>
================================================
FILE: source/components/widgets/RelatedApps.astro
================================================
---
import {shufflingArray} from '~/utils/utils.js';
const {currentApp, allApps} = Astro.props;
const candidates = allApps.filter(app =>
app.slug !== currentApp.slug
&& !app.isRedirect,
);
const scored = candidates.map(app => {
let score = 0;
for (const platform of app.platforms) {
if (currentApp.platforms.includes(platform)) {
score += 3;
}
}
if (app.isMenuBarApp && currentApp.isMenuBarApp) {
score += 2;
}
if (app.isPaid === currentApp.isPaid) {
score += 1;
}
return {app, score};
});
scored.sort((a, b) => b.score - a.score || b.app.pubDate - a.app.pubDate);
// Pick 3 with some randomness: take the top candidates and shuffle within them.
const poolSize = Math.min(scored.length, 8);
const pool = scored.slice(0, poolSize);
const related = shufflingArray(pool).slice(0, 3).map(entry => entry.app);
---
{related.length > 0 && (
<aside class="mt-32 pt-16">
<h2 class="text-center text-lg font-semibold text-gray-500 dark:text-gray-400 mb-8">You Might Also Like</h2>
<div class="flex justify-center gap-6 sm:gap-10">
{related.map(app => (
<a href={app.url} class="flex flex-col items-center gap-2 sm:gap-3 group w-20 sm:w-28">
<img
src={app.iconUrl}
width="64"
height="64"
alt={`${app.title} app icon`}
class="rounded-xl transition-transform group-hover:scale-110"
loading="lazy"
>
<span class="text-xs sm:text-sm font-medium text-gray-700 dark:text-gray-300 text-center leading-tight">{app.title}</span>
</a>
))}
</div>
</aside>
)}
================================================
FILE: source/config.mjs
================================================
export const SITE = {
name: 'Sindre Sorhus',
origin: 'https://sindresorhus.com',
basePathname: '/',
title: 'Sindre Sorhus',
description: 'Full-Time Open-Sourcerer & Aspiring Rebel',
blogPostsPerPage: 10,
};
================================================
FILE: source/content/apps/actions.md
================================================
---
title: Actions
subtitle: Additional actions for the Shortcuts app
pubDate: 2021-10-28
platforms:
- macOS
- iOS
- visionOS
hasSentry: true
appStoreId: 1586435171
links:
'TestFlight': https://testflight.apple.com/join/fJGUrsZx
olderMacOSVersions:
- '12'
- '13'
- '14'
- '15'
feedbackNote: |
### If you just updated to iOS 26, it may take some time for iOS to re-index all the Shortcuts actions. Give it some time.
### If the actions don't show up in the Shortcuts app or you get a “com.apple.extensionKit.errorDomain error 2”, [see this](/actions#actions-not-showing-up).<br><br>
Tip: To pass a variable to a file input in Shortcuts, tap-and-hold (iOS) or right-click (macOS) the input and select the variable.
**Some actions that are not possible: orientation lock status, flashlight status, ambient sensor info, flight mode status, [and more](/actions#impossible-actions).**
This is not the place to ask general Shortcuts questions. Try [r/shortcuts](https://www.reddit.com/r/shortcuts/) instead.
---
The app provides 180+ powerful extra actions for the Shortcuts app on macOS, iOS, and visionOS. These actions make it significantly easier to create shortcuts.
> [!IMPORTANT]
> Restart your device if the actions do not show up in the Shortcuts app. [Learn more ›](#actions-not-showing-up)
If you have any questions about how to use the different actions or for what, try asking the [Actions GPT bot](https://chatgpt.com/g/g-6746353a017881918cceb0761aea3bfe-actions-app-companion). And if you want to feed your own AI, [here is the source data](https://gist.githubusercontent.com/sindresorhus/fbba65a774fb9da915e624807a02a6d2/raw/7be21a65977b6dd82d1a6cc34be4476df057ea06/actions.md).
---
> [!TIP]
> On macOS, also check out [Shortcutie](/shortcutie) for advanced actions and [Short Run](/short-run) for running shortcuts from the menu bar.
---
#### Included actions
- Add to List
- Apply Capture Date
- Ask for Duration
- Ask for Input with Dialog
<span class="list-description">Show a dialog with a text field and multiple buttons. Returns both the entered text and which button was tapped, with support for timeout, custom icon (macOS), image, and destructive button styling. You can disable the text field to just have a confirmation dialog.</span>
- Ask for Text with Timeout
- Authenticate
- Blur Images
- Boolean
- Calculate Bearing
<span class="list-description">Get the compass direction between two coordinates.</span>
- Calculate Distance
- Calculate with Soulver
- Choose from List (Extended)
- Clamp Number
- Color
- Combine Audio Files
- Combine Lists
- Combine Videos
- Convert Coordinates to Location
- Convert Date to Reference Timestamp
- Convert Date to Unix Timestamp
- Convert Location to Geo URI
- Convert Number Base
<span class="list-description">Convert between binary, octal, decimal, and hexadecimal.</span>
- Convert Reference Timestamp to Date
- Convert Text File Encoding
<span class="list-description">Convert text files between character encodings (UTF-8, Shift-JIS, Windows-1252, etc.) with automatic source detection.</span>
- Convert Unix Timestamp to Date
- Counter
<span class="list-description">Atomic counter. Use cases: avoid races in concurrent automations, rate-limit runs, store progress (“step-3”), track daily counts.</span>
- Create Color Image
- Create Duration
- Create Gradient Color Image
- Create Menu Item
- Create URL
- Create URL Shortcut File
<span class="list-description">Create [`.url` or `.webloc`](https://en.wikipedia.org/wiki/Shortcut_(computing)) files that open websites when double-clicked. Primarily for macOS.</span>
- Download File
- Edit URL
- Encrypt File
- Encrypt Text
- Filter List
- Filter List of Dictionaries
- Find Music Playlist <sup>(iOS-only)</sup>
- Find Wi-Fi Network <sup>(macOS-only)</sup>
- Find Workout <sup>(iOS-only)</sup>
<span class="list-description">Returns workouts from the Health app, including workout type, duration, source details, and metrics like active calories, heart rate, etc.</span>
- Find Points of Interest
<span class="list-description">Find nearby places matching a query around a location.</span>
- Flash Screen <sup>(macOS-only)</sup>
- Format Currency
- Format Date Difference
- Format Duration
- Format Number as Ordinal
- Format Number — Compact
- Format Person Name
- Format Text List
<span class="list-description">`["A", "B", "C"]` → `A, B, and C`</span>
- Generate CSV
- Generate Emojis
- Generate Haptic Feedback <sup>(iOS-only)</sup>
- Generate Random Data
- Generate Random Text
- Generate UUID
- Get All System Colors
- Get Audio Playback Destination <sup>(iOS-only)</sup>
- Get Average Color
- Get Average Color of Image
- Get Battery State
- Get Bluetooth Device
- Get Bluetooth Devices
- Get Boolean from Input
- Get Compass Heading <sup>(iOS-only)</sup>
- Get Contents of URL (Extended)
<span class="list-description">Enhanced HTTP requests with complete response details (status codes, headers, all methods) instead of just the response body like the built-in action, and also timeout.</span>
- Get Dates in Range
<span class="list-description">Returns all dates between two dates filtered by type. For example, get all Mondays between two dates, or list every weekend in a month.</span>
- Get Default Browser <sup>(macOS-only)</sup>
- Get Device Details (Extended)
- Uptime (not including sleep)
- Uptime (including sleep)
- Active processor count
- Physical memory
- Time zone
- Hostname
- Thermal state
- Total storage capacity
- Available storage capacity
- Battery condition <sup>(macOS-only)</sup>
- Battery health <sup>(macOS-only)</sup>
- Serial number <sup>(macOS-only)</sup>
- Get Device Motion Activity
<span class="list-description">(stationary, walking, running, cycling, automotive, etc.)</span>
- Get Device Motion Data <sup>(iOS-only)</sup>
- Get Device Orientation
- Get Dominant Colors of Image
- Get Elevation <sup>(iOS-only)</sup>
- Get Emojis
- Get File Path
- Get High-Resolution Timestamp
- Get Image URLs from Web Page
<span class="list-description">Extracts image URLs from a web page and returns them without downloading.</span>
- Get Images from Web Page
<span class="list-description">Extracts images from a web page and returns them as files.</span>
- Get Index of List Item
- Get Map Image of Location
- Get Media Metadata
- Get Meta Tags of URL
<span class="list-description">Extract meta tags (title, description, Open Graph, etc.) from a webpage.</span>
- Get Modifier Key State <sup>(macOS-only)</sup>
- Get Paragraphs from Text
- Get Printers <sup>(macOS-only)</sup>
- Get Query Item Value from URL
- Get Query Items from URL
- Get Query Items from URL as Dictionary
- Get Random Boolean
- Get Random Color
- Get Random Date and Time
- Get Random Emoticon
- Get Random Floating-Point Number
- Get Random Number from Seed
- Get Raw Media Metadata
- Get Related Words
- Get Running Apps <sup>(macOS-only)</sup>
- Get Sentences from Text
- Get SF Symbol Image
- Get System Color
- Get Title of URL
- Get User Details
- Username <sup>(macOS-only)</sup>
- Full Name
- Given Name
- Family Name
- Initials
- Shell
- Language Code
- Idle Time <sup>(macOS-only)</sup>
- Administrator Status <sup>(macOS-only)</sup>
- Get Values Using [JSONPath](https://en.wikipedia.org/wiki/JSONPath)
- Get/Set Default Printer <sup>(macOS-only)</sup>
- Get/Set File Extension Visibility <sup>(macOS-only)</sup>
<span class="list-description">Check and control whether file extensions are shown in Finder for specific files. Only works if the “Show all filename extensions” Finder setting is disabled.</span>
- Get/Set File Icon <sup>(macOS-only)</sup>
<span class="list-description">Get the icon of files and folders or set custom icons for them.</span>
- Get/Set File Tags
- Get/Set Image/Video Capture Date
- Get/Set Image/Video Location
- Get/Set Uniform Type Identifier
- Global Variable
- Hex Encode
- Hide Shortcuts App
- Invert Dictionary
<span class="list-description">`{"en": "Hello", "es": "Hola"}` → `{"Hello": "en", "Hola": "es"}`</span>
- Invert Images
- Is Accessibility Feature On
- Is Audio Playing <sup>(iOS-only)</sup>
- Is Bluetooth On
- Is Call Active <sup>(iOS-only)</sup>
- Is Camera On <sup>(macOS-only)</sup>
- Is Cellular Data On
- Is Cellular Low Data Mode On
- Is Conforming to Uniform Type Identifier
- Is Connected to VPN <sup>(iOS-only)</sup>
- Is Dark Mode On
- Is Day
- Is Device Locked
- Is Device Moving
- Is Device Orientation
- Is Host Reachable
- Is Location Services Enabled
- Is Low Power Mode On
- Is Microphone On <sup>(macOS-only)</sup>
- Is Online
- Is Screen Locked <sup>(macOS-only)</sup>
- Is Screen Saver Active
- Is Shaking Device
- Is Silent Mode On <sup>(iOS-only)</sup>
- Is Time
- Is Time In Range
- Is Web Server Reachable
- Is Wi-Fi On <sup>(macOS-only)</sup>
- Join Wi-Fi <sup>(iOS-only)</sup>
- Keychain
<span class="list-description">Securely stores a value in the device [keychain](https://developer.apple.com/documentation/security/keychain-services). Useful for sensitive data like API keys, tokens, and passwords. Can be synced.</span>
- Make Live Photo from Video
- Make Markdown Table
- Manage Shortcut Lock
<span class="list-description">Prevents multiple instances of a shortcut from running simultaneously</span>
- Merge Dictionaries
- Named Clipboard <sup>(macOS-only)</sup>
- Open URLs in Safari
- Open URLs with App <sup>(macOS-only)</sup>
<span class="list-description">For example, open URLs in a specific browser.</span>
- Overwrite File
- Overlay Image (Extended)
<span class="list-description">Overlay an image on top of another one with blend modes, opacity, rotation, flipping, and precise positioning.</span>
- Parse CSV
- Parse JSON5
- Parse Markdown Table
- Pick Color
<span class="list-description">Pick a color using the system color picker, optionally from a reference image.</span>
- Play Alert Sound <sup>(macOS-only)</sup>
- Pretty Print Dictionaries
- Remove Dictionary Values
- Remove Duplicate Lines
- Remove Duplicates from List
- Remove Emojis
- Remove Empty Lines
- Remove from List
- Remove Non-Printable Characters
- Reverse Lines
- Reverse List
- Round Number to Decimal Places
<span class="list-description">`3.14159` → `3.14`</span>
- Round Number to Multiple
- Sample Color from Screen <sup>(macOS-only)</sup>
- Scan Barcodes in Image
- Scan Documents <sup>(iOS-only)</sup>
- Scan QR Codes in Image
- Send Distributed Notification <sup>(macOS-only)</sup>
- [What are distributed notifications?](/apps/faq#distributed-notifications)
- Set Creation and Modification Date of File
- Set Dictionary Value Using [JSONPath](https://en.wikipedia.org/wiki/JSONPath)
- Show Black Screen <sup>(iOS-only)</sup>
- Show Notification
- Shuffle List
- Sort List
- Sort List of Dictionaries
- Sort Months
- Spell Out Number
- Toggle Boolean
- Transform Lists
- Transform Text
- Camel case
- Pascal case
- Snake case
- Constant case
- Dash case
- Slugify
- Strip punctuation
- Strip quotation marks
- Strip HTML
- Strip diacritics
- JSON Escape
- Transliterate to Latin
- Transliterate Latin to Arabic
- Transliterate Latin to Cyrillic
- Transliterate Latin to Greek
- Transliterate Latin to Hebrew
- Transliterate Latin to Hangul
- Transliterate Latin to Hiragana
- Transliterate Latin to Thai
- Transliterate Hiragana to Katakana
- Transliterate Mandarin to Latin
- Transform Text with JavaScript
- Trim Whitespace
- Truncate List
- Truncate Number
- Truncate Text
- Use System Font in Rich Text
- [Example shortcut](https://www.icloud.com/shortcuts/03aecdb46eca496aaf996ebc625a0c54)
- Wait for Distributed Notification <sup>(macOS-only)</sup>
- [What are distributed notifications?](/apps/faq#distributed-notifications)
- Wait Milliseconds
- Write or Edit Text
#### Want more shortcut actions? {#more-actions}
- Run shortcuts from the menu bar or silently in the background via URL scheme → [Short Run](/short-run)
- High-quality transcription (speech to text) in 100 languages → [Aiko](/aiko)
- Trigger shortcuts on your Mac from your iOS device → [Hyperduck](/hyperduck#shortcuts)
- Set default browser → [Supercharge](/supercharge) & [Default Browser](/default-browser)
- Use the ChatGPT API, Ollama, Groq → [AI Actions](/ai-actions)
- Show text in menu bar → [One Thing](/one-thing)
- Open URLs in a specific browser → [Velja](/velja)
- Remove tracking parameters from URLs → [Velja](/velja) & [Pure Paste](/pure-paste)
- Check if online → [Online Check](/online-check)
- Generate images from text with AI locally → [Imago](/imago)
- Clear clipboard formatting → [Pure Paste](/pure-paste)
- Get internet speed → [Speediness](/speediness)
- Join video calls → [Dato](/dato)
- Put text on the iOS Lock Screen → [Any Text](/any-text)
- Preview app icons → [Icon Preview](/icon-preview)
- Get clipboard items → [Pasteboard Viewer](/pasteboard-viewer)
<!-- - Get random animated GIF → [Jiffy](/jiffy) -->
#### Impossible actions {#impossible-actions}
Some common action requests that are not possible:
- Orientation lock status
- Flashlight status
- Ambient sensor info
- Flight mode status
- Hotspot status
- Hotspot connect/disconnect
- All audio playback destinations
- CarPlay connection status
- Notifications in CarPlay
- Media volume
- More accessibility checks (like reduce white point)
- If charging wirelessly
Anything related to changing system features/settings or interacting with other apps is generally not possible.
For these, I recommend sending a [feature request to Apple](https://feedbackassistant.apple.com).
#### Declined actions {#declined-actions}
- Imgur - I generally don't want to integrate with services. They cause a huge support burden, either by being unreliable, breaking the API, shutting down, and other things.
## Tips
### URL Scheme {#url-scheme}
The app supports the `actions://` URL scheme that can be used to open the app.
## Frequently Asked Questions {#faq}
#### The actions don't show up in the Shortcuts app {#actions-not-showing-up}
This is caused by an iOS/macOS bug.
Some things you could try:
1. Restart your device.
1. Change the device language to something else and back.
1. Add [this shortcut](https://www.icloud.com/shortcuts/14315b9af3774a0c8cb439718a67fb2f), run it once, relaunch Shortcuts, and see if the actions show up in the Shortcuts app after that.
1. Add [this shortcut](https://www.icloud.com/shortcuts/e3b39e37d8d6439db9119ebbff626958), copy the action, paste it into a new shortcut, and relaunch Shortcuts.
1. Remove the app, install it again, and restart your device.
*Please don't contact me about this issue. This is a problem with iOS/macOS and out of my control.*
#### I get a “errorDomain error 2” error when running an action
Same solution as above.
#### Why is this free without ads?
I just enjoy making apps and want this to be available for everyone. Consider leaving a nice review on the App Store.
#### How can I prevent the app from being offloaded when I have “app offloading” enabled on iOS?
iOS does not have a way to prevent individual apps from being offloaded (even though it should!) and there is no way for apps to tell iOS not to offload them. I recommend [sending feedback to Apple](https://feedbackassistant.apple.com) about this. You could try [this workaround](https://www.reddit.com/r/ios/comments/85k8b5/disable_offloading_for_specific_apps/).
#### Can the “Show Notification” action send critical alerts?
No. I applied for Apple’s [Critical Alerts entitlement](https://developer.apple.com/documentation/bundleresources/entitlements/com.apple.developer.usernotifications.critical-alerts), but it was declined.
Critical Alerts are reserved for very limited use cases such as medical, health, home security, and public safety notifications. General-purpose automation apps like Actions are not eligible.
## Older versions
- [3.8.0](https://www.dropbox.com/scl/fi/fhfw330g14eh35bwofuyy/Actions-3.8.0-macOS-15-1773919013.zip?rlkey=9l9f3noc5l64j9r0cai9lc5rm&raw=1) for macOS 15+
- [3.5.1](https://github.com/user-attachments/files/18963268/Actions.3.5.1.-.macOS.14.zip) for macOS 14+
- [2.10.0](https://www.dropbox.com/scl/fi/lzy4po8qfggroxcv9pzdo/Actions-2.10.0-1731826197.zip?rlkey=f37xihlhq45syauygdn5268un&raw=1) for macOS 13+
- [1.13.1](https://www.dropbox.com/scl/fi/9iqfn8airygpk0la4gv1u/Actions-1.13.1-1731826428.zip?rlkey=y4u5ni2pn28rp3lse08lv96k6&raw=1) for macOS 12+
## Non-App Store Version
A special macOS version for users that cannot access the App Store. It won't receive automatic updates. I will update it here once a year.
[Download](https://www.dropbox.com/scl/fi/7mt9uvbmn589y4qobdpe9/Actions-4.0.1-1774194992.zip?rlkey=7tg0zlun69c19t6m5lmn2ph0q&raw=1) *(4.0.1 · macOS 26+)*
================================================
FILE: source/content/apps/ai-actions.md
================================================
---
title: AI Actions
subtitle: AI actions for the Shortcuts app
pubDate: 2023-09-26
platforms:
- macOS
- iOS
- visionOS
appStoreId: 6465250302
olderMacOSVersions:
- '14'
- '15'
feedbackNote: |
I cannot provide support for general Shortcuts questions. Use [Reddit](https://www.reddit.com/r/shortcuts) for that.
---
The app provides additional AI-related actions (GPT 5.2, Claude Sonnet/Opus 4.5, etc.) for the Shortcuts app.
For example, an action to interact with the ChatGPT API.
> [!NOTE]
> The app requires you to specify your own OpenAI / Anthropic API key.
> Note that ChatGPT Plus or an Anthropic paid account does not give you free API access.
Your API key is securely stored in your keychain, not in a shortcut.
It also supports many more models through [Ollama and Groq](#alternative-providers).
> [!NOTE]
> The macOS version on the App Store requires an Apple silicon Mac. For Intel Macs, use the [non-App Store version](#non-app-store-version).
> *(This is because Apple only accepted the iOS version and not the macOS version, so on macOS, the iOS version of the app is used, which only runs on Apple silicon Macs)*
<!-- **Apple is currently blocking updates for the iOS app, so I won't be able to submit an update for some time... I plan to get it [published to an alternative App Store](https://appleinsider.com/articles/23/08/15/setapp-plans-to-launch-eu-only-alternative-ios-app-store) in 2024.** -->
<br>
> [!TIP]
> You may also like my [Actions](/actions) app.
## Tips
#### Ollama and Groq support {#alternative-providers}
The app also supports [Ollama](https://ollama.com/blog/openai-compatibility) (local models like GGUF) and [Groq](https://console.groq.com/docs/openai) (because they have OpenAI API compatibility), making it possible to use it with a lot more models.
For Ollama, set the “Base URL” to `http://localhost:11434` (or the network address of your Ollama instance). Since Ollama doesn't require authentication, just enter any text (e.g., `ollama`) as the OpenAI API key. In the “Ask AI” action, select the “Custom” model and provide the name of the desired model (e.g., “llama3”).
For Groq, specify `https://api.groq.com/openai`. In the “Ask AI” action, select the “Custom” model and provide the name of the desired model.
For OpenRouter, specify `https://openrouter.ai/api`.
For [Gemini](https://ai.google.dev/gemini-api/docs/openai), specify `https://generativelanguage.googleapis.com/v1beta/openai/`. In the “Ask AI” action, select the “Custom” model and provide the name of the desired model.
## Frequently Asked Questions {#faq}
#### The actions do not show up in the Shortcuts app
This is an iOS/macOS bug. Launch the app once and then restart your device. If that doesn't work, [try this.](https://webtrickz.com/third-party-lock-screen-widgets-not-showing-ios-16/)
#### Why are these actions not just part of your [Actions](/actions) app?
Apple prevents any app that includes AI-related functionality from being available in China. I didn't want the Actions app to be unavailable in China just because of one action.
#### How is this better than the “Ask ChatGPT” action provided by the official ChatGPT app?
This one works on macOS too, supports longer text, has customizability options for power-users, supports DALL·E, and will support more AI APIs in the future.
#### How is this better than just calling the OpenAI API directly from Shortcuts?
This makes it simpler, but more importantly, it stores your API key securely in the keychain. This means you can share your shortcuts with others without exposing your API key. The API key is not stored in the shortcut.
#### Can you support the OpenAI Whisper API?
No, the Whisper API isn't suitable for this app due to Shortcuts' 30-second limit on third-party actions on iOS, making long transcriptions impossible. Instead, use my app [Aiko](/aiko). It runs Whisper locally on your device and supports Shortcuts by performing transcriptions in the foreground, bypassing the time constraint (on macOS, it runs in the background).
#### Can you add built-in support for the Google Gemini API? {#gemini}
No. I don’t want to keep adding more providers, and I especially don’t want to take on Google-specific APIs and auth quirks. More providers means a larger API surface, more edge-cases, and more maintenance.
Workaround: Gemini already offers an OpenAI-compatible endpoint, which this app supports. Set the Base URL to `https://generativelanguage.googleapis.com/v1beta/openai/`, then choose “Custom” and enter the Gemini model name. You can also use an OpenAI-compatible proxy like [OpenRouter](https://openrouter.ai) if you prefer one unified endpoint.
#### Why is this free without ads?
I just enjoy making apps. Consider leaving a nice review on the App Store.
#### Can you localize the app into my language?
I don't plan to localize the app.
## Older Versions
- [1.4.5](https://www.dropbox.com/scl/fi/o80d948mabpohlip3je6m/AI-Actions-1.4.5-macOS-15-1769233269.zip?rlkey=lgxnxyzv75g6r82b4c3fitwuz&raw=1) for macOS 15+
- [1.3.3](https://github.com/user-attachments/files/18376675/AI.Actions.1.3.3.-.macOS.14.zip) for macOS 14+
## Non-App Store Version
A special version for users that cannot access the App Store. It won't receive automatic updates. I will update it here once a year.
[Download](https://www.dropbox.com/scl/fi/6l6e13n3v01nywhx532cp/AI-Actions-1.5.0-1769231336.zip?rlkey=hv3jek3xtx0l3sv7m8oip1y78&raw=1) *(1.5.0)*
*Requires macOS 26 or later*
================================================
FILE: source/content/apps/aiko.md
================================================
---
title: Aiko
subtitle: AI-powered audio transcription
pubDate: 2023-03-03
platforms:
- macOS
- iOS
- visionOS
isPaid: true
appStoreId: 1672085276
olderMacOSVersions:
- '13'
- '14'
feedbackNote: |
**Sharing from Voice Memos on iOS 26 does not work because of an iOS 26 bug outside of my control.** You may notice that many targets do work. This is because
those apps use share extensions, while with Aiko, it opens directly in the app. [Workaround.](/aiko#voice-memos-ios26)
[How can I get back the old app icon?](/aiko#old-icon)
[Refunds](/apps/faq#refund)
If the app crashes, it's likely that the device ran out of available RAM. Restart your device and try again.
No need to contact me about Whisper v3 turbo support. I'm looking into it.
Any problems with the output are unfortunately out of my control. The app uses the OpenAI Whisper AI model to transcribe. The model has some flaws with certain recordings like repetition, hallucination, and refusal to produce text.
---
High-quality on-device transcription. Easily convert speech to text from meetings, lectures, and more.
The transcription is powered by OpenAI's [Whisper model](https://openai.com/research/whisper) running locally on your device.
The app also includes [support for Shortcuts](#tips).
It's a [Universal Purchase](/apps/faq#universal-purchase).
<details>
<summary><b>Supports audio in 100 languages</b></summary>
- Afrikaans
- Albanian
- Amharic
- Arabic
- Armenian
- Assamese
- Azerbaijani
- Bangla
- Bashkir
- Basque
- Belarusian
- Bosnian
- Breton
- Bulgarian
- Burmese
- Catalan
- Chinese
- Croatian
- Czech
- Danish
- Dutch
- English
- Estonian
- Faroese
- Finnish
- French
- Galician
- Georgian
- German
- Greek
- Gujarati
- Haitian Creole
- Hausa
- Hawaiian
- Hebrew
- Hindi
- Hungarian
- Icelandic
- Indonesian
- Italian
- Japanese
- Javanese
- Kannada
- Kazakh
- Khmer
- Korean
- Lao
- Latin
- Latvian
- Lingala
- Lithuanian
- Luxembourgish
- Macedonian
- Malagasy
- Malay
- Malayalam
- Maltese
- Marathi
- Mongolian
- Māori
- Nepali
- Norwegian
- Norwegian Nynorsk
- Occitan
- Pashto
- Persian
- Polish
- Portuguese
- Punjabi
- Romanian
- Russian
- Sanskrit
- Serbian
- Shona
- Sindhi
- Sinhala
- Slovak
- Slovenian
- Somali
- Spanish
- Swahili
- Swedish
- Tagalog
- Tajik
- Tamil
- Tatar
- Telugu
- Thai
- Tibetan
- Turkish
- Turkmen
- Ukrainian
- Urdu
- Uzbek
- Vietnamese
- Welsh
- Yiddish
- Yoruba
</details>
#### Privacy
Aiko transcribes audio directly on your device, ensuring complete privacy. It's perfect for sensitive recordings.
#### Technical details
The app uses the Whisper large v2 model on macOS and the medium or small model on iOS depending on available memory.
## Trial
Try Aiko free for 14 days via [TestFlight](https://testflight.apple.com/join/P1qnhHCC). It's the full app, no limitations. No auto-charges or commitment. Simply purchase it from the App Store after the trial if you want to continue using it.
*Disregard where it says how many days there are left. It means the days left of the current TestFlight build, not how long you have left on your trial.*
## Tips
### Divide text into paragraphs
Aiko divides the transcription text by sentences. If you want the text divided into paragraphs, copy the text from Aiko, go to [ChatGPT](https://chat.openai.com), and use the following prompt.
`Divide the text into paragraphs. Don't change the text otherwise: TRANSCRIPTION TEXT`
### Fix missing punctuation
A flaw of the Whisper model is that transcriptions can sometimes be missing punctuation. Try setting the “Prompt” setting to, for example:
> Hello. I like cake.
If that still doesn't fix it, try copying the text from Aiko, go to [ChatGPT](https://chat.openai.com), and use this prompt: `Fix the missing punctuation. Don't change the text otherwise: TRANSCRIPTION TEXT`
### Batch transcribe {#batch}
Aiko does not yet support batch transcription built-in, but you can achieve it with shortcuts.
Get [this (iOS)](https://www.icloud.com/shortcuts/f790a41e23ae4222920277b4fe9d1217) or [this (macOS)](https://www.icloud.com/shortcuts/0be44e478b9e472192cae2e0dfc327ed) shortcut and then share the audio files you want to transcribe (e.g. from Voice Memos or Files/Finder) and choose the shortcut in the share sheet. You can also run the shortcut directly from the Shortcuts app or even add the shortcut to the Home Screen.
### Transcribe files directly in Finder
On macOS, you can transcribe files simply by right-clicking audio files in Finder and choosing [this shortcut](https://www.icloud.com/shortcuts/d03bb8e17513432190a1ed711f99d423) (add it first) in "Quick Actions". [Preview.](https://x.com/sindresorhus/status/1789957043912093954) In the shortcut you can choose whether you want text or subtitles.
### Record and transcribe by pressing the iPhone action button
[This](https://www.icloud.com/shortcuts/62a62ef967b74ffb897d72ee6a881746) shortcut records, transcribes, and then shows the result in the Aiko app. Save the shortcut and then select it in the action button settings.
If you want to record, transcribe, and then do something with the transcription in your shortcut workflow, check out [this shortcut](https://www.icloud.com/shortcuts/00198bd63c094540ba25fe066245319d). You could, for example, pass the transcription to the ChatGPT shortcut action for further processing.
### Quickly record and transcribe (iOS)
Do the same as the above, but instead add the shortcut to the Home Screen (can be done in the shortcut settings).
### Quickly record, transcribe, and add transcription to the Notes app (iOS)
Use [this shortcut](https://www.icloud.com/shortcuts/806ab945539d42acb79354805c50d9d5).
### Quickly record and transcribe (macOS)
You can use [this shortcut](https://www.icloud.com/shortcuts/e43220d72f3343659e0fda36fee52d72) to be able to quickly record, transcribe, and have the result copied to the clipboard. The shortcut can be triggered from the menu bar or you can set a global keyboard shortcut for it.
### Start recording in Aiko when tapping the Home Screen icon
[Get this shortcut](https://www.icloud.com/shortcuts/7c3031aa674c405fa69093d1f6c184a6) and add it to the Home Screen. Then tap it instead of the original Aiko app icon.
## Frequently Asked Questions {#faq}
#### Can you use the large v3 model for the Mac app?
The v3 model is [worse](https://github.com/openai/whisper/discussions/1762#discussioncomment-7532295) than v2 in too many cases. I tried releasing v3, but got a lot of emails about the quality being worse, so I ended up reverting it.
#### Can you add support for v3 turbo?
I have plans to look into it, but it's not something I have time to prioritize right now. It cannot be the default model as it's worse than v2. Which means, I will need to add support for downloading models, which is a huge amount of work.
#### Can you include the large model on iOS?
Even the latest iPhone is not powerful enough to run the large model. It can maybe be done when the [Whisper Distilled](https://github.com/huggingface/distil-whisper) project supports multiple languages.
#### Can you support the new [Apple SpeechTranscriber API](https://developer.apple.com/documentation/speech/speechtranscriber)?
Probably not initially:
- New Apple APIs are always super buggy
- Only 10 languages
- No automatic language detection
- Whisper still has higher quality
Maybe when it's more mature.
#### The screen turned off during transcription
The app tells the system not to turn off the screen. However, if you have enabled “low power mode”, the system may do so anyway. Try turning it off.
#### Can I edit the text in the app?
I don't plan to support any editing. Export the transcription and edit it in a proper text editor.
#### How is this better than the built-in transcription on Apple devices?
- Much better accuracy.
- Support for more languages.
- Transcribe audio and video files.
- Export to many different formats, like JSON, CSV, and subtitles.
#### I found a mistake in the transcription
The app uses the OpenAI Whisper model and I have no control over the quality of its output. You could provide feedback about the problem [here](https://github.com/openai/whisper/discussions/categories/general).
#### My language is not in the list of supported languages. Can you support it?
I have no control over the supported languages. You could try to request it [here](https://github.com/openai/whisper/discussions/categories/general).
#### The transcription repeats itself many times
This is unfortunately a flaw in the Whisper AI model and out of my control. This is usually caused by the audio not being clean (for example, a lot of background noise).
Some things you could try:
- Restart your device.
- Try enabling the “Skip silent parts” setting.
- Try enabling the “Reduce repetitions” setting.
- Try enabling the “Reduce repetitions even more” setting.
- If you don't need timestamps, you can disable them being produced, which can sometimes reduce repetitions. Triple-tap on the “Translate to English” text in the settings and then disable the “Produce timestamps” setting.
#### The transcription is missing punctuation
This is unfortunately a flaw in the Whisper model. [Workaround.](#tips)
#### The transcription includes a sentence at the end that was not in the audio
This is unfortunately a flaw in the Whisper model. It can sometimes add a sentence like “Thanks for watching!” to the end. There is not much I can do about this.
Workaround: Try enabling the “Skip silent parts” setting.
This issue arises from quirks in the AI's processing, where it sometimes generates off-topic content, often due to data remnants or misinterpreted context. These are not messages or 'whispers' with any underlying meaning; they're random anomalies that OpenAI is actively working to correct.
#### The transcription is not in the same language as the source audio
Ensure the "Translate to English" setting is disabled.
The language used in the "Prompt" setting may also affect the transcription language.
#### The transcription is in Traditional Chinese while the audio was in Simplified Chinese or the inverse
The [Whisper AI model](https://github.com/openai/whisper) used by the app does not differentiate between Traditional Chinese and Simplified Chinese, so the result could unfortunately end up with either. [Learn more.](https://github.com/openai/whisper/discussions/277)
Try writing a sentence in Traditional Chinese or Simplified Chinese in the “Prompt” setting in the app to steer the model into using the right one.
#### Why must I keep the iOS app open while it transcribes?
iOS apps are fundamentally restricted from operating in the background for extended periods. This ironically even [affects Apple's official apps](https://x.com/bzamayo/status/1661133704792621059).
#### What file formats does it support?
Any audio and video format that macOS and iOS supports. For example: `.m4a`, `.wav`, `.mp3`, `.mp4`, `.mov`. It does not support `.ogg`.
#### Can I get both the original transcription and the English translation at the same time?
No, the AI model processes either transcription or translation, not both simultaneously. You need to run the process twice: once for the original transcription, and again with the “Translate to English” setting enabled.
#### Where can I find the audio recordings?
The audio recordings can be found in the “Aiko” folder in the Files app.
#### How can I delete audio recordings?
Recordings are not automatically deleted after transcription.
**macOS:** Click “File › Show Recent Recordings” in the menu bar to open the recordings folder in Finder. Delete them from there.
**iOS:** Open the Files app and navigate to the “Aiko” folder.
You can also enable “Auto-delete recordings older than 7 days” in settings.
#### When trying to import an audio file, I get error -50
The error comes from iOS and means that it could not read the audio file. Sometimes [converting](https://apps.apple.com/app/id1081480270) the audio file to a different format, like MP3, resolves the issue.
#### How can I transcribe audio from the Voice Memos app?
**macOS:** Drag and drop the memo into the Aiko window. Note that because of a macOS bug, this can sometimes crash Aiko. If this happens, try sharing the memo from the Voice Memos app to Aiko instead.
**iOS:** In the Voice Memos app, tap the memo, tap the `…` button, tap `Share`, and choose Aiko in the app list.
**iOS 26:** Sharing from Voice Memos is broken due to an iOS bug. See [workaround](#voice-memos-ios26).
#### Sharing from Voice Memos does not work on iOS 26 {#voice-memos-ios26}
This is caused by an iOS 26 bug outside of my control. As a workaround, you can use a shortcut that appears in the Voice Memos share sheet:
1. Install the [this shorcut](https://www.icloud.com/shortcuts/343553f2aff44c0fb1c7974a969ae4bb).
1. In Voice Memos, share the recording.
1. Look for **Transcribe with Aiko** in the share sheet. If you don't see it, scroll to the end of the app row and tap `Edit Actions`.
1. If it's still not listed, open the Shortcuts app, tap the **Transcribe with Aiko** shortcut, tap the `ⓘ` button, and enable “Show in Share Sheet”.
#### Why does it take so long to generate?
Several factors can affect the transcription speed, including the performance of your device and the amount of available memory and CPU. Try closing down other apps or restarting your device before transcribing.
That being said, it's likely Aiko will become significantly faster in the coming months.
#### Why does the app take up so much space on disk and memory?
The app delivers the highest quality transcription on the market for 100 different languages. Rather than asking why it's so large, the real question is how is it so small.
#### The app is overheating my device
The role of the operating system (iOS/macOS) is to effectively manage the system's resources and to safeguard against overheating. Apps are designed to utilize as many resources as they need to function optimally. In the event that resource consumption reaches a point that threatens to overheat the device, it's the operating system's job to limit such usage automatically.
If your device is experiencing overheating while using the app, it's important to understand that the issue likely originates either from the operating system's inability to manage resources effectively, or from an underlying hardware problem. In either case, the app itself is not responsible for the overheating.
#### Can I delete some of the languages to save space?
This is unfortunately not possible. The model has all the languages stored together in a way that makes it impossible to remove just some languages.
#### Can you support real-time transcription?
This is something I plan to look into, but I have more popular requests I need to prioritize first.
#### Can you support naming the people in the audio? {#diarization}
This is called [Diarization](https://en.wikipedia.org/wiki/Speaker_diarisation). It's something I would like to support, but it has to first be [implemented in the library](https://github.com/ggerganov/whisper.cpp/issues/64) the app uses.
#### How can I transcribe a Zoom meeting? {#zoom}
The app does not yet support live transcription, but you could record the Zoom meeting, and after the meeting is finished, drop the recording into the Aiko window to transcribe.
#### How can I transcribe a Messages voice note? {#messages}
Drag and drop the voice note into Aiko.
[How to drag and drop on iPhone.](https://www.imore.com/how-use-drag-and-drop-iphone)
#### How can I transcribe a Telegram voice note? {#telegram}
Telegram voice notes are stored in the format [Ogg](https://en.wikipedia.org/wiki/Ogg), which macOS/iOS cannot handle.
Workaround for iOS:
1. Download [this app](https://apps.apple.com/app/id889643660).
2. In Telegram, share the voice note to “Audio Converter”.
3. Select “AAC” as output format and tap the convert button.
4. Tap the share button and then choose Aiko.
Workaround for macOS:
1. Download [this app](https://apps.apple.com/app/id1081480270)
2. In Telegram, right-click the voice note and save it.
3. Open the saved voice note with the “Audio Converter” app.
4. Select “AAC” as output format and tap the convert button.
5. Save the converted file and open it with Aiko.
*I would also recommend sending feedback to Telegram that they should support M4A for voice notes.*
#### How can I export the transcription as subtitles (SRT)?
When the transcription is done, click the save button in the toolbar, and choose “SRT”.
#### How can I transcribe a YouTube video?
Download the audio using a service like [dirpy](https://dirpy.com) or the macOS app [Downie](https://software.charliemonroe.net/downie/) and then open the file in Aiko.
This cannot be supported built-in as downloading videos from YouTube is against their Terms of Service and Apple would likely reject such a feature.
#### The app supports translating to English, can it support more languages?
The translation support is built into the AI model and it only supports translating to English. You could copy-paste the result into ChatGPT or Google Translate.
#### How can I trigger Aiko with a custom URL scheme?
Aiko does not have a custom URL scheme, but you can trigger Aiko from the Shortcuts app, and the Shortcuts app does have a [custom URL scheme](https://support.apple.com/guide/shortcuts/run-a-shortcut-from-a-url-apd624386f42/ios).
#### What is Flash Attention? {#flash-attention}
Flash Attention is a special technique that helps the app process audio more efficiently while using less memory on your device. Think of it as a smarter way to handle the heavy lifting of transcription. It's a setting in case it causes any problem. It should not though.
#### How can I change the app icon on macOS? {#change-icon}
You can do it manually for free. See [this guide](https://www.macstories.net/tutorials/customizing-app-icons-on-a-mac-in-2023/).
You can also use the [Replaceicon](https://replacicon.app) app (paid).
#### How can I get back the old robot icon? {#old-icon}
**iOS:** There is a setting for it in the app.
**macOS:** Unlike iOS, macOS does not have the ability to have alternative icons. See the above FAQ. [Here's the old app icon.](https://www.dropbox.com/scl/fi/rr8hizeqejfz0pg5yll7f/Aiko-1772609366.png?rlkey=v5frkozme3iairlshont7vxhd&raw=1)
#### How is Aiko pronounced?
IPA (International Phonetic Alphabet): `[a.i.ko̞]`
English approximation: `ah-ee-ko`
#### Is the app native?
Yes, it's native and written in Swift and SwiftUI.
#### Can you localize the app into my language?
I don't plan to localize the app.
## Older Versions
- [1.8.2](https://drive.google.com/file/d/1ZKZ5P17Pvv4CYuBtkfDe5cuJw46S1HoE/view?usp=sharing) for macOS 14
- [1.5.3](https://drive.google.com/file/d/15NOcj4fyX58I3_NlQyCziL87Ru89yFRx/view?usp=sharing) for macOS 13
These are free for everyone but they will not run on newer macOS versions.
================================================
FILE: source/content/apps/amazing-ai.md
================================================
---
title: Amazing AI
subtitle: Generate images from text using Stable Diffusion
pubDate: 2022-12-21
platforms:
- macOS
- iOS
- visionOS
appStoreId: 1660147028
hasSentry: true
olderMacOSVersions:
- '13'
- '14'
- '15'
---
Simply describe the image you desire, and the app will generate it for you!
It runs locally on your device.
**Note:** It uses Stable Diffusion 1.5, which is flexible, but it requires a detailed description to generate a usable image.
> [!WARNING]
> On macOS, developed exclusively for Apple silicon - The app is NOT compatible with devices running on Intel chips.\
> On iOS, it requires at minimum an iPhone 15 Pro or iPad with an M1 processor.
> [!TIP]
> Check out my [Imago](/imago) app, which uses Flux 2 instead — a much better model.
[Stable Diffusion](https://en.wikipedia.org/wiki/Stable_Diffusion) is a deep learning, text-to-image model used to generate detailed images conditioned on text descriptions.
The app is [highly optimized](https://machinelearning.apple.com/research/stable-diffusion-coreml-apple-silicon) and runs on the [Apple Neural Engine](https://apple.fandom.com/wiki/Neural_Engine).
## Tips
### Preview
Click a thumbnail to view a larger version of it. Click again to exit.
### Negative prompt
To write a [negative prompt](https://dreamlike.art/guides/guide-to-stable-diffusion-negative-prompt-parameter) (what to exclude), write `##` after your prompt, followed by your negative prompt. For example, “photo of a cake, high-quality ## strawberry, out of frame”, where `strawberry, out of frame` is your negative prompt. Anything after the `##` is your negative prompt. You only write `##` once.
### Keyboard shortcuts
On macOS, when in preview mode, there are some keyboard shortcuts available:
- <kbd>◀</kbd> — Previous image
- <kbd>▶</kbd> — Next image
- <kbd>Space</kbd> — Save image
- <kbd>Command+C</kbd> — Copy image
- <kbd>Esc</kbd> — Exit preview
### Metadata
On macOS, when you save a generated image, it includes a lot of useful metadata (prompt, steps, etc). You can [view this in Finder](https://x.com/sindresorhus/status/1611441129622278146/photo/1) by right-clicking the image file and selecting “Get Info”. The file also includes some relevant tags which can be used to create [smart folders](https://support.apple.com/guide/mac-help/tag-files-and-folders-mchlp15236/mac).
## Frequently Asked Questions {#faq}
#### Why not use Stable Diffusion 3?
It will eventually be supported, but right now, it's worse than 1.5.
#### Why does the app require Apple silicon for Macs?
The app takes advantage of recent [optimizations by Apple](https://machinelearning.apple.com/research/stable-diffusion-coreml-apple-silicon).
#### Why does the app require at least iPhone 15 Pro and iPad M1?
Generating images with Stable Diffusion requires a lot of system resources. It would not be a good experience on older devices. It could probably run fine on iPhone 15 and iPhone 14 Pro, but Apple does not let us do such a fine-grained requirement. Either I require the current devices or I have to support devices down to iPhone XS, which are not nearly powerful enough.
#### What are the usage restrictions for the generated images?
You can use the images for commercial or non-commercial purposes, but you must adhere to the [Creative ML OpenRAIL-M license's usage restrictions](https://github.com/CompVis/stable-diffusion/blob/21f890f9da3cfbeaba8e2ac3c425ee9e998d5229/LICENSE#L69-L82). These restrictions include not using the images for illegal activity, false information, discrimination, or medical advice.
#### Can you support custom models?
I don't plan to support this. This app is intentionally simple. There are many other apps that support custom models.
#### Can you support inpainting/outpainting?
I don't plan to support this. [DiffusionBee](https://diffusionbee.com) supports this (see below for comparison).
#### Can it generate images with aspect ratios other than a square?
The Stable Diffusion library used by this app only supports squares.
#### Why can it not generate adult images?
The app would not be allowed on the App Store if it allowed creating such images.
#### Why does it take so long to generate?
Several factors can affect the speed of image generation, including the performance of your device and the amount of available memory and CPU. Try closing down other apps or restarting your device before generating images.
And bear in mind that the initial generation after installing the app may take longer due to model validation.
#### Why does the app take up so much space on disk and memory?
The AI model used to generate images is large. This is reasonable given the model's capabilities.
#### How does it compare to [DiffusionBee](https://github.com/divamgupta/diffusionbee-stable-diffusion-ui)? {#diffusionbee}
**Amazing AI benefits**
- Faster and more energy-efficient as it uses the [Apple Neural Engine](https://apple.fandom.com/wiki/Neural_Engine) and recent [macOS optimizations](https://machinelearning.apple.com/research/stable-diffusion-coreml-apple-silicon)
- Native user interface (DiffusionBee is a web app wrapped with Electron which does not follow platform conventions)
- Batch generation of different prompts (DiffusionBee supports batch for the same prompt only)
- Shortcuts support
- Automatic upscaling (DiffusionBee requires you to manually click an upscale button for each image)
- Sandboxed (More secure)
- Available on the App Store
**DiffusionBee benefits**
- Inpainting
- Outpainting
- Image-to-image
- Custom models
#### Why is this free without ads?
I just enjoy making apps. Consider leaving a nice review on the App Store.
## Older Versions
- [1.6.0](https://github.com/sindresorhus/sindresorhus.github.com/releases/download/v1.0.0/Amazing.AI.1.6.0.zip) for macOS 15+
- [1.5.0](https://github.com/sindresorhus/sindresorhus.github.com/releases/download/v1.0.0/Amazing.AI.1.5.0.zip) for macOS 14+
- [1.2.2](https://drive.google.com/file/d/1mcEhAKhmQGYzmSS-zlejt3_qsKFzqm0h/view?usp=sharing) for macOS 13+
## Non-App Store Version
A special version for users that cannot access the App Store. It won't receive automatic updates. I will update it here once a year.
[Download](https://github.com/sindresorhus/sindresorhus.github.com/releases/download/v1.0.0/Amazing.AI.1.7.0.zip) *(1.7.0)*
*Requires macOS 26 or later*
================================================
FILE: source/content/apps/any-text.md
================================================
---
title: Any Text
subtitle: Put text on your Lock Screen, Home Screen, and desktop
pubDate: 2022-09-12
platforms:
- macOS
- iOS
- watchOS
- visionOS
isPaid: true
appStoreId: 1643199620
feedbackNote: |
If you are having problems with sync, [read this](/any-text#troubleshoot-syncing).
---
The app provides widgets where you can write any kind of text. It could be an important note, your goal, a list of tasks, etc.
For macOS, it's only available for Apple silicon Macs running macOS 26 or later.
On iOS, you can also show the text in a Live Activity.
Syncs seamlessly across your devices with iCloud.
<br>
> [!TIP]
> You may also like [my similar app](/one-thing) for macOS.
## Tips
### Markdown {#markdown}
You can style parts of the text bold, italic, or strikethrough using [Markdown](https://www.markdownguide.org/basic-syntax/).
For example:
- **Bold text** is created by wrapping text with double asterisks: `**bold**`
- *Italic text* is created by wrapping text with single asterisks: `*italic*`
- ~~Strikethrough text~~ is created by wrapping text with double tildes: `~~strikethrough~~`
### Troubleshoot syncing {#troubleshoot-syncing}
- After enabling sync, try writing some more text on all the devices.
- [More…](/apps/faq#icloud-sync)
## Frequently Asked Questions {#faq}
#### How do I add the widget?
- [iOS](https://support.apple.com/HT207122)
- [macOS](https://support.apple.com/guide/mac-help/mchl52be5da5/mac)
- [watchOS](https://support.apple.com/guide/watch/see-widgets-in-the-smart-stack-apdecf142fb9/watchos)
#### The widget does not show up in the widget picker, the widget is stuck, or is missing from the Home Screen
The iOS widget system is quite buggy and can fail a lot. This is not a problem with the app and out of my control. [Try this.](https://webtrickz.com/third-party-lock-screen-widgets-not-showing-ios-16/)
#### The widget is blank
Try this:
- Restart your device.
- Change the language of the device to something else and then back.
- Ensure Lock Screen widgets are allowed to show content while the device is locked at “Settings › Face ID & Passcode › Allow Access When Locked › Lock Screen Widgets”.
#### The Lock Screen text sometimes disappears
Make sure Lock Screen widgets are allowed when locked: “Settings › Face ID & Passcode › Allow Access When Locked › Lock Screen Widgets”. If it’s “off”, iOS may hide the widget until you unlock.
#### Can you support having multiple pieces of text that change during the day?
I would like to keep the app simple, so it's not something I plan to support built-in. However, the app comes with a shortcut action to change the text, so you could use the [Shortcuts automations](https://support.apple.com/guide/shortcuts/apdfbdbd7123/7.0/ios/17.0) to change the text during the day.
You could also put multiple widgets in a [widget stack](https://support.apple.com/118610).
*(On macOS 26, you can use Shortcuts automations. On older macOS versions, you can use [Shortery](https://apps.apple.com/app/id1594183810).)*
#### Can you add support for user-installed fonts?
This is unfortunately not possible as widgets cannot access user-installed fonts.
#### Can I make the widget horizontally centered on the Lock Screen?
This is unfortunately not possible. Apple has decided that the rectangular widget can only appear on the left or right side.
#### Can I pick a color for the text on the Lock Screen?
Lock Screen widgets cannot have colors. You can set a custom text color for the normal widgets though.
#### Can I pick a background color for the Lock Screen widgets?
Same answer as the above.
#### The widget does not update if I write some text in the app and then reveal the Lock Screen
You need to first close the app. This is an iOS bug.
If you work at Apple → [FB11522275](https://github.com/feedback-assistant/reports/issues/360)
#### The widget does not update even if I do the above
The app tells iOS to update the widget, unfortunately, iOS can decide to delay an update for various reasons (low battery, low-power mode, etc). This is completely out of my control.
#### The widget does not update when setting the text with the Shortcuts action
This is unfortunately an iOS bug. The app correctly tells iOS to update the widget, but iOS delays it for some reason. The text will update eventually.
If you work at Apple → [FB11522170](https://github.com/feedback-assistant/reports/issues/359)
#### Can you make the widget bigger?
The widget sizes are controlled by Apple. The provided size is the largest it allows.
#### Can you make the widget background transparent?
This is not possible.
#### Can you remove the title shown below the widget?
Apple does not allow removing the title. Some apps managed to do it early on, but these days, Apple rejects any attempt at doing that. However, in iOS 18 you can hide the title for all apps and widgets.
#### How can I remove the date prefix from the inline Lock Screen widget above the clock?
iOS forces the date to be shown. This is out of my control.
#### The inline Lock Screen widget above the clock does not respect my font choice
iOS forces the text to be the same style as the prefixed date. This is out of my control.
#### Can it open a specific app instead when tapping the widget?
Create a shortcut in the Shortcuts app that opens the app you want, then open “Any Text”, go to one of the widgets, open settings, and set the tap action to the shortcut you just made.
#### Can I prevent my child from editing the text when tapping the widget?
You can set the “Widget Tap Action” setting to “None”.
#### Can I edit the text directly from the Home Screen or Lock Screen?
No, widgets only support tapping interactions.
#### The Lock Screen widget does not show the text after restarting the device, before unlocking it
This is an iOS limitation and is out of my control. It shows a placeholder until the first unlock. This is how all Lock Screen widgets work.
#### When using the “Run Shortcut” action, why does tapping the widget first open the main app and then the Shortcuts app?
This is because of iOS limitations. A widget can only open its own app when a user taps it. And the only way to run a shortcut is to open the Shortcuts app using a special URL. So when you tap the widget, the widget opens the main app, and the main app then opens the Shortcuts app. It's not a very good user experience, but only Apple can fix this.
If you work at Apple, you know what to do:
- [FB9745173](https://github.com/feedback-assistant/reports/issues/240)
- [FB11516334](https://github.com/feedback-assistant/reports/issues/357)
- [FB11516273](https://github.com/feedback-assistant/reports/issues/356)
#### Can you localize the app into my language?
I don't plan to localize the app.
## Scripting
The text in the widgets can be changed using the Shortcuts app.
### Shortcuts app
- [Shortcuts usage guide](https://www.xda-developers.com/guide-shortcuts-macos/)
- [How to run shortcuts from the command-line on macOS](https://support.apple.com/guide/shortcuts-mac/run-shortcuts-from-the-command-line-apd455c82f02/mac)
### Command-line on macOS
Shortcuts can be executed via the command-line, allowing you to set widget text programmatically.
For example, to set the text for widget 1, add [this shortcut](https://www.icloud.com/shortcuts/6873c23a3cbb4718b23135e367d6be1b), and then run this:
```sh
echo 'TEST' | shortcuts run 'Set Widget 1 Text'
```
================================================
FILE: source/content/apps/app-buddy.md
================================================
---
title: App Buddy
subtitle: Helper for my apps
pubDate: 2024-10-20
platforms:
- macOS
hasSentry: true
releasesRepo: app-buddy-meta
mainLinks:
'Download': https://github.com/sindresorhus/app-buddy-meta/releases/latest/download/App.Buddy.zip
requirement: Requires macOS 26 or later
olderMacOSVersions:
- '15'
---
This app provides support functionality for [my apps](/apps). It offers easy ways to export/import (backup/transfer) settings, reset privacy permissions, and more. It's a separate app because some features are not possible in sandboxed apps, which most of my apps are.
I welcome suggestions for what more useful support tools it could contain.
*I also have future plans to make this app provide extra functionality for my sandboxed apps.*

## Frequently Asked Questions {#faq}
#### Can it support apps other than yours?
No. This is intended for my apps only.
If you need app setting import/export for any apps, check out my [Supercharge](/supercharge) app.
#### Why is this not in the App Store?
Much of the functionality would not be possible in the App Store because of [sandboxing](/apps/faq#macos-sandbox).
## Older Versions
- [1.2.1](https://www.dropbox.com/scl/fi/tffgghwhnido39kz4z32k/App-Buddy-1.2.1-macOS-15-1769050534.zip?rlkey=00isw08dwxyri87dt360gstwi&raw=1) for macOS 15+
================================================
FILE: source/content/apps/ask-ai.md
================================================
---
title: Ask AI
subtitle: Use ChatGPT right on your watch
pubDate: 2023-03-12
platforms:
- watchOS
appStoreId: 6446167837
isPaid: true
---
Experience the power of [ChatGPT](https://en.wikipedia.org/wiki/ChatGPT) as your very own personal assistant, right on your wrist! Get instant answers to any question you have, whether it's explaining complex topics, translating languages, providing recommendations, solving math problems, improving your writing, and so much more. I highly recommend [exploring ChatGPT's capabilities](https://www.google.com/search?client=safari&rls=en&q=chatgpt+usage+ideas&ie=UTF-8&oe=UTF-8) and discovering how it can simplify your life.
The app is in English, but you can ask questions in many languages, including: English, Spanish, French, German, Chinese, Japanese, Korean, Portuguese, Italian, Russian, Arabic, Dutch, Swedish, Norwegian, Danish, Finnish, Turkish, Hebrew, Hindi, Bengali, Thai, Greek, Polish, Romanian, Ukrainian, Vietnamese, Indonesian, Malay, Swahili, Tagalog, Tamil, Kannada, Telugu, Marathi, Gujarati, Punjabi, and Nepali.
The app uses [GPT-4o mini](https://openai.com/index/gpt-4o-mini-advancing-cost-efficient-intelligence/).
#### Technical details
The app uses OpenAI's official ChatGPT API. I have to pay for every question, but the app is a one-time purchase since I hate subscriptions. I sure hope I estimated the price correctly 🤣
## Frequently Asked Questions {#faq}
#### I bought the app on my iPhone/iPad but it does not show up on my watch
This is a bug in the App Store. App developers have no control over the install process of apps. Try restarting your watch and if it still does not show up, go into the App Store on your watch and download it there. You will not have to pay again.
#### Can it open the voice dictation directly at launch?
This is unfortunately not possible as watchOS only supports opening the keyboard.
#### Can I choose a voice?
The app automatically uses the best voice for the language used in the answer. Unfortunately, the high-quality Siri voices are not available for apps to use.
#### Can I launch it with the action button?
Add [this shortcut](https://www.icloud.com/shortcuts/6b890da159844407a6b39de454567c97) to one of your Apple devices (not the watch), and then on the watch, select the shortcut in the action button configuration.
#### Can you support iOS and macOS too?
Unfortunately, it is unlikely that the app will be available on iOS and macOS. The pricing of the app is based on its expected lifetime usage, and since I am charged for the amount of usage, the cost would be much higher on iOS. For macOS, check out [QuickGPT](/quickgpt).
================================================
FILE: source/content/apps/battery-indicator.md
================================================
---
title: Battery Indicator
subtitle: Remaining battery time in your menu bar
pubDate: 2017-02-18
platforms:
- macOS
appStoreId: 1206020918
isPaid: true
isMenuBarApp: true
hasSentry: true
olderMacOSVersions:
- '10.14'
- '10.15'
- '11'
- '12'
- '13'
- '14'
- '15'
---
Quickly glance at the remaining battery time or percentage right in your menu bar.
## Frequently Asked Questions {#faq}
#### The app does not show up in the menu bar
[Try this](/apps/faq#app-not-showing-in-menu-bar)
You may also have enabled the “Hide while on power” preference, which hides the menu bar icon while the power adapter is connected. Launch the app again to reveal the menu bar item for 5 seconds or disconnect the power adapter.
#### The estimated time left is incorrect
The number comes from macOS and the app has no control over it.
#### The menu bar icon is vertically stretched when shown on a secondary display
This is a macOS 11 bug. I have tried to work around this issue, but it's out of my control.
#### Why does the menu bar icon show `…` when I unplug the power adapter?
The system needs some time to accurately calculate the time remaining estimate.
#### How do I remove the system battery menu bar item?
Drag it out of the menu bar while pressing <kbd>Command</kbd>.
#### Can it show “apps using significant energy” like the built-in battery indicator?
It can unfortunately not show this because of restrictions ([sandboxing](/apps/faq#macos-sandbox)) imposed on apps on the App Store. However, you could change the menu bar item type to text instead of the icon and use this app in combination with the system battery indicator.
#### Can it have a “charge to full now” button?
This is not possible for the same reason as mentioned above.
#### Can it play a sound when the battery is charged a certain percentage? {#notification-sound}
The app has a built-in sound when showing notifications. However, if you want a different sound, you can disable the default notification sound in the “Notification Settings” and then follow the below steps.
This is a perfect use case for the built-in Shortcuts app. You can use the `Play Sound` action to play the sound you want. To run the shortcut when the battery is at a certain percentage, you can use Shortcuts automations on macOS 26, or the [Shortery app](https://apps.apple.com/app/id1594183810) on older macOS versions. Use its “Power Status” trigger.
You can find sound effects [here](https://pixabay.com/sound-effects/search/interface/).
#### Can the battery icon hide when the battery is charged a certain percentage?
This is a perfect use case for the built-in Shortcuts app. Create a shortcut that quits the app and one that launches it. To run the shortcut when the battery is at a certain percentage, you can use Shortcuts automations on macOS 26, or the [Shortery app](https://apps.apple.com/app/id1594183810) on older macOS versions. Use its “Power Status” trigger.
## Older Versions
- [2.19.0](https://www.dropbox.com/scl/fi/14amy0g1r6sjyhg48cjns/Battery-Indicator-2.19.0-macOS-15-1772299240.zip?rlkey=e647a9azxyif2mnyuqot8jya7&raw=1) for macOS 15
- [2.18.0](https://github.com/user-attachments/files/19015442/Battery.Indicator.2.18.0.-.macOS.14.zip) for macOS 14
- [2.16.1](https://github.com/sindresorhus/meta/files/13942534/Battery.Indicator.2.16.1.-.macOS.13.zip) for macOS 13
- [2.14.2](https://github.com/sindresorhus/meta/files/10759031/Battery.Indicator.2.14.2.-.macOS.12.zip) for macOS 12
- [2.12.3](https://github.com/sindresorhus/meta/files/8759816/Battery.Indicator.2.12.3.-.macOS.11.zip) for macOS 11
- [2.7.1](https://github.com/sindresorhus/meta/files/6565005/Battery.Indicator.2.7.1.-.macOS.10.15.zip) for macOS 10.15
- [2.1.0](https://github.com/sindresorhus/meta/files/4127047/Battery-Indicator-2.1.0-Mojave.zip) for macOS 10.14
These are free for everyone but they will not run on newer macOS versions.
================================================
FILE: source/content/apps/black-out.md
================================================
---
title: Black Out
subtitle: Hide sensitive parts of an image
pubDate: 2017-12-01
platforms:
- macOS
isPaid: true
appStoreId: 1319884285
hasSentry: true
olderMacOSVersions:
- '10.15'
- '11'
- '12'
- '13'
- '14'
---
This app can be useful when you want to post a screenshot or photo on the web that contains some information you don’t want to be revealed. Maybe you want to share a screenshot of a Slack conversation on X (Twitter) but hide some private information. It also removes all metadata, like when and where a photo was captured.
## Frequently Asked Questions {#faq}
#### Can you support blurring and pixelation?
Blurring and pixelation are intentionally not supported as they can sometimes [be reversed](https://dheera.net/projects/blur). The only reliable way to redact something is to put a black box over it.
#### I can already do this in the Preview app!
You can do this in any graphics app. The point of this app is to make the task super easy to do. Most graphics apps, like Preview, Pixelmator, and Photoshop, preserve metadata, which means you could accidentally leak information like the capture location. Black Out strips out all metadata. It can also be run directly from Finder as a [Quick Action](https://support.apple.com/guide/mac-help/mchl97ff9142/mac).
#### Does it support PDF?
You can open a PDF document, but you have to export it as a PNG image. It’s almost impossible to reliably export redacted PDFs.
#### What is the text in the icon?
It’s from Apple’s inspirational [“Here’s to the Crazy Ones” TV commercial](https://www.youtube.com/watch?v=-z4NS2zdrZc).
## Older Versions
- [2.4.0](https://github.com/user-attachments/files/18210600/Black.Out.2.4.0.-.macOS.14.zip) for macOS 14
- [2.3.1](https://github.com/sindresorhus/meta/files/13923936/Black.Out.2.3.1.-.macOS.13.zip) for macOS 13
- [2.2.0](https://github.com/sindresorhus/meta/files/10773680/Black.Out.2.2.0.-.macOS.12.zip) for macOS 12
- [2.0.4](https://github.com/sindresorhus/meta/files/8759655/Black.Out.2.0.4.-.macOS.11.zip) for macOS 11
- [1.8.2](https://github.com/sindresorhus/meta/files/7454156/Black.Out.1.8.2.-.macOS.10.15.zip) for macOS 10.15
These are free for everyone but they will not run on newer macOS versions.
================================================
FILE: source/content/apps/blear.md
================================================
---
title: Blear
subtitle: Transform photos into blurry wallpapers
pubDate: 2015-06-09
platforms:
- iOS
repoUrl: https://github.com/sindresorhus/blear
appStoreId: 994182280
---
Transform your photos or the bundled ones into stunning blurry wallpapers for your device. Make your Home/Lock screen shine!
================================================
FILE: source/content/apps/camera-preview.md
================================================
---
title: Camera Preview
subtitle: Preview your webcam and take photos
pubDate: 2023-05-20
platforms:
- macOS
isPaid: true
isMenuBarApp: true
appStoreId: 1632827132
olderMacOSVersions:
- '13'
- '14'
- '15'
---
Instant access to your Mac's camera feed for quick checks before video calls.
## Tips
- Press the <kbd>Return</kbd> or <kbd>Space</kbd> key while showing the camera feed to take a photo.
- Press <kbd>Command+</kbd> to zoom in, <kbd>Command−</kbd> to zoom out, and <kbd>Command+0</kbd> to reset the zoom.
- Press the <kbd>Option</kbd> key while resizing the window to resize from the center (this works with any app).
## Frequently Asked Questions {#faq}
#### The app does not work {#not-working}
- Ensure you are on the latest version.
- Restart your computer.
- Try [resetting permissions](/apps/faq#mac-reset-permissions).
#### Can you add support for making the camera feed a circle?
I don't plan to add that. I plan to make a separate app specifically for showing the camera on presentations and screencasts, which will have this feature.
#### Can it float over fullscreen apps?
Yes, when in menu bar mode.
#### How is this better than Photo Booth? {#photo-booth}
- Convenient access from the menu bar.
- Toggle it via a keyboard shortcut.
- Higher quality camera output.
- Does not crop the camera output.
- Minimalistic design with no window frame.
- Takes photos without the countdown.
- Photos are saved to the file system, not hidden inside the app.
- The window can be made to always stay on top of other windows.
- Can be accessed from the menu bar.
- Capture and copy photo in a single action.
- Save photo as lossless PNG file.
- Includes camera metadata (EXIF) in the saved photo.
- Made by an indie developer that listens to users.
#### How is this better than QuickTime? {#quicktime}
- Shows the camera faster. One click instead of multiple.
- Convenient access from the menu bar.
- Toggle it via a keyboard shortcut.
- Remembers window size and position.
- Takes photos.
- The window can be made to always stay on top of other windows.
- Capture and copy photo in a single action.
#### What resources are used when the app is in the menu bar?
When the camera window is closed or minimized, the camera is turned off. The app consumes approximately 40 MB of RAM and 0% of CPU when running in the background.
#### Do you plan to add background removal?
I don't have any immediate plans for this. Maybe in a year when AI background removal has progressed further.
#### Do you plan to add filters?
No.
#### Can it record video?
No. That's outside the scope of this app. You can use the built-in QuickTime Player app for that.
<!-- #### Why is this free without ads?
I just enjoy making apps. Consider leaving a nice review on the App Store. -->
#### Can you localize the app into my language?
I don't plan to localize the app.
## Older Versions
- [1.7.7](https://www.dropbox.com/scl/fi/dhbgwns59on2uw6zb4uql/Camera-Preview-1.7.7-macOS-15-1772349679.zip?rlkey=yhusqz0f82kdaovk2exod1w3j&raw=1) for macOS 15
- [1.6.1](https://github.com/user-attachments/files/18385375/Camera.Preview.1.6.1.-.macOS.14.zip) for macOS 14
- [1.4.0](https://github.com/sindresorhus/meta/files/13988612/Camera.Preview.1.4.0.-.macOS.13.zip) for macOS 13
These are free for everyone but they will not run on newer macOS versions.
================================================
FILE: source/content/apps/caprine.md
================================================
---
isUnlisted: true
title: Caprine
subtitle: Elegant Facebook Messenger desktop app
pubDate: 2015-09-16
platforms:
- macOS
- Linux
- Windows
repoUrl: https://github.com/sindresorhus/caprine
---
An open-source, cross-platform, and privacy-focused Facebook Messenger desktop app.
================================================
FILE: source/content/apps/command-x.md
================================================
---
title: Command X
subtitle: Cut and paste files in Finder
pubDate: 2023-04-30
platforms:
- macOS
isPaid: true
isMenuBarApp: true
appStoreId: 6448461551
hasSentry: true
olderMacOSVersions:
- '13'
- '14'
- '15'
pressQuotes:
- quote: If you do a lot of file management and need to move items in Finder, this app will make your work much more straightforward. It’s objectively better than Apple’s standard shortcut, and pretty much everyone can benefit from it.
source: Softpedia
url: https://mac.softpedia.com/get/System-Utilities/Command-X.shtml
feedbackNote: |
[The app randomly disappears/quits](/apps/faq#randomly-quits)
---
Cut and paste files and folders in Finder using Command+X and Command+V. Without this app, you have to first copy (Command+C) and then remember to move (Option+Command+V).
Known limitation: You cannot cut the name of a file when editing a filename in Finder or cut when using the search field. [Learn more.](#textfield-limitation)
### Mentions
- [Review by Softpedia](https://mac.softpedia.com/get/System-Utilities/Command-X.shtml)
- [10 Mac Apps That Will Change How You Use macOS in](https://www.youtube.com/watch?v=LtuUwACZdsQ&t=426s)
<br>
> [!TIP]
> You may also like my [Supercharge](/supercharge) app which has an [improved implementation](#textfield-limitation) of this.
## Frequently Asked Questions {#faq}
#### Why? I can already use <kbd>Option+Command+V</kbd>
- It's more logical to cut & paste than copy & move.
- Consistency and muscle memory benefits if you also use Linux or Windows.
#### The app does not show up in the menu bar
[Try this](/apps/faq#app-not-showing-in-menu-bar)
#### The app does not work {#not-working}
First try relaunching the app. If that doesn't help, try restarting your computer.
Then, make sure you pressed <kbd>Command+X</kbd> and not <kbd>Command+C</kbd>.
To make sure you used the app correctly, try this: Select a file in Finder, press <kbd>Command+X</kbd>, change to a different folder, press <kbd>Command+V</kbd>. The file should have been moved to this new folder.
**Note:** You cannot cut, highlight a folder, and then paste. You have to actually go into the folder to paste to it. That's just how Finder works. Same with copy-pasting.
**It could also be that certain apps (password managers and browsers) are [interfering with the app](/apps/faq#secure-input-problem).**
If still not working, try closing down all apps and menu bar items, just to rule out some other app interfering.
Then try toggling the setting “Use more reliable way of handling Command+X”, and try the above steps again. If it works then, please report it to me.
If it's still not working, try this: Select a file in Finder, press <kbd>Command+C</kbd>, change to a different folder, press <kbd>Option+Command+V</kbd>. The file should have been moved to this new folder. If this did not work, the problem is not this app, as those are the keyboard shortcuts it simulates.
If it's a work computer, your company may have something installed that prevents the app from working.
Try uninstalling and reinstalling the app, and restart your computer.
If it's still not working, try re-granting accessibility access:
1. Open “System Settings › Privacy & Security › Accessibility”
2. Remove Command X from the list
3. Quit and reopen Command X
4. Grant accessibility access when prompted
The last thing you could try is to reset the permissions. Either use [App Buddy](/app-buddy), or quit the app, and run this in the Terminal app:
```sh
tccutil reset All com.sindresorhus.Command-X
```
To help me figure out the issue, make sure the “Use more reliable way of handling Command+X” setting is enabled, press <kbd>Command+X</kbd> and <kbd>Command+V</kbd> in Finder, click the “Copy Debug Info” button in the Command X menu bar menu, and then [send the debug info to me](/feedback?product=Command%20X&referrer=Website-FAQ), including a short explanation of what didn't work.
#### How does the app work?
The app works by overriding the normal cut <kbd>⌘X</kbd> keyboard shortcut when Finder is active and executes a copy <kbd>⌘C</kbd> instead. When you then paste <kbd>⌘V</kbd>, it executes the native move <kbd>⌥⌘V</kbd> keyboard shortcut. So really, it's Finder moving the files. This app just makes the keyboard shortcuts more intuitive.
#### Is there any risk of data loss if I forget to paste?
No. The files are not touched until you paste. If you don't paste, the files just stay in place.
#### Can I move files by clicking the “Paste” menu item?
No, you can only use the keyboard shortcuts. The app works by overriding the original keyboard shortcuts. There is no way to override the Finder menu items.
#### Can it make the cut files in Finder have less opacity?
This is not possible. The app works by overriding some key combinations. It doesn't and cannot modify Finder in any way.
#### It does not work when I try to paste directly to an expanded subfolder shown in its parent folder
This is a Finder bug. You can reproduce it even without Command X by selecting the file to move, pressing <kbd>Command+C</kbd>, selecting the destination folder, and then pressing <kbd>Option+Command+V</kbd>.
#### It does not work when I try to paste into a folder in column view where the parent is a tag
Same as the above.
#### I am not able to cut text when editing a filename in Finder {#textfield-limitation}
This is a known issue that is unfortunately not fixable. The app works by overriding the normal cut keyboard shortcut when Finder is active, which also affects cutting text in a filename. There is no way to differentiate between cutting a file and cutting text in a filename in Finder. The main reason this is not possible is because of restrictions ([sandboxing](/apps/faq#macos-sandbox)) imposed on apps on the App Store. My [Supercharge](/supercharge) app has the Command X feature without this rename limitation because it's not on the App Store.
#### I am not able to cut text in the search field in Finder
Same as the above.
#### Can you localize the app into my language?
I don't plan to localize the app.
## Older Versions
- [1.6.2](https://www.dropbox.com/scl/fi/90rakqppxdnryctolu9rc/Command-X-1.6.2-macOS-15-1775377612.zip?rlkey=hwh8im5sol3bnc7chqjursf7a&raw=1) for macOS 15
- [1.4.7](https://github.com/user-attachments/files/19031153/Command.X.1.4.7.-.macOS.14.zip) for macOS 14
- [1.3.1](https://github.com/sindresorhus/meta/files/13987707/Command.X.1.3.1.-.macOS.13.zip) for macOS 13
These are free for everyone but they will not run on newer macOS versions.
================================================
FILE: source/content/apps/dato.md
================================================
---
title: Dato
subtitle: Menu bar calendar and world clocks, plus fullscreen meeting notifications
pubDate: 2019-07-13
platforms:
- macOS
isPaid: true
isMenuBarApp: true
hasSentry: true
appStoreId: 1470584107
setappId: 571
olderMacOSVersions:
- '10.14'
- '10.15'
- '11'
- '12'
- '13'
- '14'
pressQuotes:
- quote: Dato is a simple app, but it includes a wide variety of settings that make it more flexible than you might imagine. […] I’ve already got plenty of apps in my menu bar, so I’m always reluctant to add more. However, Dato has stuck around because of its flexibility.
source: MacStories
url: https://www.macstories.net/reviews/dato-review-calendar-events-and-time-zones-from-your-macs-menu-bar/
- quote: Is this why you never call?
source: Mom
feedbackNote: |
If a menu bar icon is missing, [this](/apps/faq#app-not-showing-in-menu-bar).
If you notice the mouse pointer shaking when opening Dato, this is a macOS 26 bug, and outside the control of Dato.
If text in the app is upside down on macOS 26, it's a macOS bug and unrelated to the app. A computer restart fixes it.
[The app randomly disappears/quits](/apps/faq#randomly-quits)
---
Dato gives you a local clock, date, and multiple world clocks in the menu bar. When you click Dato in the menu bar, you get a menu with a calendar, calendar events, and world clocks. All of this is highly customizable.
Dato is a one-time purchase on the App Store with a lifetime of updates.
<br>
<sup>(Equivalent to two months of Fantastical subscription)</sup>
[MacStories review of Dato.](https://www.macstories.net/reviews/dato-review-calendar-events-and-time-zones-from-your-macs-menu-bar/)
#### Features
- Calendar, optionally with week numbers and event & reminder indicators.
- Your upcoming events for the next week (customizable) at a glance.
- Fullscreen meeting notifications.
- Reminders support.
- Time zones in the Dato menu, optionally with custom names.
- Show the upcoming event in the menu bar (like Fantastical, Meeter, and MeetingBar)
- Time travel for time zones.
- Deduplicates identical events from different calendars
- Create events (even with a global keyboard shortcut)
- Join the next video call meeting with a customizable global keyboard shortcut
- Clocks for multiple time zones in the menu bar.
- Custom format for the date & time in the menu bar.
- Highlight certain days of the week in the calendar.
- Search time zones by city (15k cities included offline).
- Supports all calendar services that the built-in Calendar app supports (iCloud, Google, Outlook, etc).
- Fully customizable.
- Lots of in-app keyboard shortcuts for power users.
- Global keyboard shortcut to open/close the app.
- Supports calendar events with HTML formatted notes.
- Show seconds in the menu bar clock or in the menu. (Optional)
- Integration with Zoom, Google Meet, Microsoft Teams, and 50+ other services.
- And the ability to add support for any other video call service yourself.
- Open calendar events from Google Calendar directly in Google Calendar on the web.
- Comes with multiple menu bar icons to choose from: date in calendar, date with border (like Itsycal), static clock, none.
- Large text mode.
- Date calculator.
- Hourly chime.
##### Supported video call services {#supported-video-call-services}
- 8x8
- Amazon Chime
- Around
- BlueJeans
- Cal.com
- Chorus
- CoScreen
- Demio
- Demodesk
- Dialpad
- Doxy.me
- FaceTime
- Gather
- Gong
- Google Meet
- GoToMeeting
- GoToWebinar
- Huddle01
- Jam
- Jitsi Meet
- Lark
- LiveKit Meet
- Livestorm
- Luma
- Meetecho
- Microsoft Teams
- oVice
- Pop
- Preply
- Pumble
- Reclaim
- Relayed
- RingCentral
- Session
- Signal
- Skype
- Slack
- StreamYard
- TeamViewer
- Teemyco
- Tuple
- UserZoom
- Venue
- Vimeo
- Vonage
- VooV
- Vowel
- Webex
- Whereby
- Workplace Chat
- Zhumu
- Zoho Cliq
- Zoom
*And you can add support for any other video call service yourself in the app.*
---
If all you need is another clock in the menu bar, check out [Second Clock](/second-clock).
---
## Trial
Try the fully functional trial [here](https://www.dropbox.com/scl/fi/7202xt4ctcndv3mln3qz1/Dato-5.7.2-trial-1772863857.zip?rlkey=137ou1l0182qpleurvnlylbrn&raw=1). The only limitation is a reminder to buy the app every 12 hours, and no automatic updates. All data and settings carry over if you buy it on the App Store.
*Download it to the Downloads folder, double-click to unzip, and then move it to the `/Applications` folder.*
You can also [try it on Setapp](https://go.setapp.com/stp181?refAppID=571&utm_medium=vendor_program&utm_content=button) for 7 days for free.
## Tips
<table>
<tr>
<td>
Double-click an event in the event list to open it in the default calendar app, if possible.
</td>
</tr>
<tr>
<td>
Click the month & year label in the calendar (for example, “April 2020”) to change the selected day to “today”. Right-click it to quickly go to a specific date.
</td>
</tr>
<tr>
<td>
Long-press a day in the calendar to open that day in the default calendar app. (Supports: Calendar, Fantastical 2, BusyCal, Outlook)
</td>
</tr>
<tr>
<td>
Hold <kbd>option</kbd> while clicking the calendar arrows to jump a year instead of a month.
</td>
</tr>
<tr>
<td>
Hold <kbd>option</kbd> while dragging the time travel slider to skip by 15 minutes instead of an hour.
</td>
</tr>
<tr>
<td>
If you open the “new event” window while the time travel slider is active, the event will default to the time of the slider.
</td>
</tr>
</table>
### Keyboard Shortcuts
#### General
<table>
<tr>
<td>
<kbd>◀</kbd>/<kbd>▶</kbd>
</td>
<td>Previous/next day in the calendar</td>
</tr>
<tr>
<td>
<kbd>▲</kbd>/<kbd>▼</kbd>
</td>
<td>Same day in the previous/next week in the calendar</td>
</tr>
<tr>
<td class="whitespace-nowrap">
<kbd>option+◀</kbd>
<br>
<kbd>option+▶</kbd>
</td>
<td>Previous/next month in the calendar</td>
</tr>
<tr>
<td class="whitespace-nowrap">
<kbd>shift+option+◀</kbd>
<br>
<kbd>shift+option+▶</kbd>
</td>
<td>Previous/next year in the calendar</td>
</tr>
<tr>
<td>
<kbd>space</kbd>
</td>
<td>Select today in the calendar</td>
</tr>
<tr>
<td>
<kbd>n</kbd>
</td>
<td>Create a new event</td>
</tr>
<tr>
<td>
<kbd>p</kbd>
</td>
<td>Toggle window pinning</td>
</tr>
<tr>
<td>
<kbd>c</kbd>
</td>
<td>Show the date & time calculator</td>
</tr>
<tr>
<td>
<kbd>j</kbd>
</td>
<td>Join the current/upcoming Zoom/Meet/Teams meeting (works in the Dato menu and the “upcoming event in menu bar” menu)</td>
</tr>
<tr>
<td>
<kbd>o</kbd>
</td>
<td>Open the default calendar app</td>
</tr>
<tr>
<td>
<kbd>command+q</kbd>
</td>
<td>Quit the app</td>
</tr>
</table>
#### Fullscreen notifications
<table>
<tr>
<td>
<kbd>esc</kbd>
</td>
<td>Dismiss notification</td>
</tr>
<tr>
<td>
<kbd>return</kbd>
</td>
<td>Run the default action (highlighted button)</td>
</tr>
</table>
#### Time travel
<table>
<tr>
<td class="whitespace-nowrap">
<kbd>command+◀</kbd>
<br>
<kbd>command+▶</kbd>
</td>
<td>Activate time travel and offset it by one step backwards or forwards</td>
</tr>
<tr>
<td>
<kbd>esc</kbd> / <kbd>space</kbd>
</td>
<td>Deactivate time travel</td>
</tr>
</table>
#### New event & reminder window
<table>
<tr>
<td>
<kbd>control+tab</kbd>
</td>
<td>Switch between new event and new reminder</td>
</tr>
</table>
### Gestures
<table>
<tr>
<td>
Double-click an event in the event list
</td>
<td>Open the event in the default calendar app, if possible</td>
</tr>
<tr>
<td>
Swipe left/right on the calendar
</td>
<td>Next/previous month in the calendar</td>
</tr>
<tr>
<td>
<kbd>option</kbd> + Swipe left/right on the calendar
</td>
<td>Next/previous year in the calendar</td>
</tr>
<tr>
<td>
<kbd>shift</kbd> + Swipe left/right on the calendar
</td>
<td>Next/previous day in the calendar</td>
</tr>
</table>
## Frequently Asked Questions {#faq}
#### The app does not show up in the menu bar
[Try this](/apps/faq#app-not-showing-in-menu-bar)
#### Dato does not work with Ice
This is an [issue with Ice](https://github.com/jordanbaird/Ice/discussions/298) and must be fixed there.
#### I have multiple menu bar items that open Dato
Dato can potentially have multiple menu bar items:
- The main one
- Upcoming event
- Time zone in the menu bar
You can choose which one of these to show in the menu bar in the app settings.
#### Can I buy Dato from outside the App Store and Setapp?
No. Dato is only available from the App Store and Setapp.
#### Dato quit suddenly
Check if there are any [crash reports](/apps/faq#crash-report). If none exists, it's likely macOS terminated Dato because it needed to reclaim memory. This is an especially common problem on MacBook Air laptops with only 8 GB RAM. Try restarting your computer.
#### Some calendars are missing {#missing-calendars}
Dato simply fetches calendars and events from macOS. If something is missing, it's never caused by Dato.
Make sure:
- The calendars show in the Calendar app and that they are enabled there.
- Open the Calendar app settings, click the “Accounts” pane, and then check that the calendars are there. Dato can only show calendars added there.
- The calendars are enabled in the Dato settings.
- Open the Dato settings, click the “Events” tab, and make sure the calendars are enabled.
- [The calendar events may not yet have been fetched by macOS](#refresh-interval)
- You have tried restarting your computer.
- You are on the latest version of macOS.
- You have tried resetting permissions for Dato using [App Buddy](/app-buddy).
Some users had luck with removing the account from the Calendar app settings and re-adding it.
[Contact me](/feedback?product=Dato&referrer=Website-FAQ) if you have tried all this and you are still having issues. I'm not aware of any issue that was not one of the things mentioned above.
#### Some calendar events are missing in Dato {#missing-events}
Make sure:
- The calendar with the event is enabled in Dato.
- You are on the latest Dato and macOS versions.
- You have tried restarting your computer.
- The event is not a declined event, which Dato does not show.
- You have not hidden the event using the “Hide” action in the event's context menu.
- You have not excluded the event with the “Exclude events” setting.
- The event shows up in the Calendar app.
- If it does not show up there, the problem is not with Dato.
- Try pressing <kbd>Command+R</kbd> in the Calendar app to force-refresh.
- Try signing out and in again of the account in the Calendar app settings. That has helped a few users.
- [Microsoft Bookings has problems syncing to MacBooks.](https://answers.microsoft.com/en-us/outlook_com/forum/all/bookings-meetings-sync-with-iphone-but-not-with/085530b3-90d2-4792-b0d9-0cc6f52875ba?page=3)
#### The “upcoming event in menu bar” notification is not showing up {#upcoming-event-in-menu-bar-troubleshooting}
Make sure:
- The feature is enabled in the settings.
- The correct calendars for it are enabled (it has a separate calendar picker).
- When in the settings for it, the placeholder example menu bar item shows up in the menu bar.
- If it doesn't show up, try reducing the “event title limit”.
- There is enough space in the menu bar to show it.
- You are on the latest Dato and macOS versions.
- You have tried restarting your computer.
- If you have Bartender or Ice (or a similar app that hides menu bar items) installed, make sure the menu bar item was not auto-hidden by them.
- Note that it uses a separate menu item from the main Dato menu item, so it could still be hidden by Bartender/Ice while the main menu bar item is not.
- Try quitting Bartender/Ice to make sure it is not the one causing the issue.
- If you are using Ice, see [this](https://github.com/jordanbaird/Ice/discussions/298).
- As a workaround, in the “upcoming event in menu bar” settings, you could choose to keep the menu bar item visible even when there are no upcoming events.
- The event is not an all-day event (which are not shown).
- You have not muted the event.
- You have not excluded the event with the “Exclude events” setting.
- If you have “Show for video call events only” enabled, ensure the event shows a video call icon in the event list.
- If you have “Show for events with an alert only” enabled, ensure the event has an alert.
- If you have “Show only for accepted events” enabled, ensure the event is accepted.
#### Fullscreen notifications do not work {#fullscreen-notifications-troubleshooting}
Make sure:
- The fullscreen notifications setting is enabled.
- You have selected the correct calendars in the fullscreen notifications settings.
- You are on the latest Dato and macOS versions.
- You have tried restarting your computer.
- The event is not an all-day event (which are not shown).
- The event shows in the Calendar app.
- You have not muted the event.
- You have not excluded the event with the “Exclude events” setting.
- You have not already joined the event in the last 15 minutes.
- You have not paused fullscreen notification from a [Focus Filter](https://support.apple.com/guide/mac-help/mchl613dc43f/mac).
- If you have “Show for video call events only” enabled, ensure the event shows a video call icon in the event list.
- If you have “Show for events with an alert only” enabled, ensure the event has an alert.
- If you have “Show only for accepted events” enabled, ensure the event is accepted.
- If it's a Google calendar, it may be caused by [sync issues](#google-calendar-sync-issue).
#### The Dato menu bar item is not faded out on inactive displays
This is a macOS bug. macOS replicates the menu bar item on inactive displays and this handling is outside the control of apps. The reason it does not happen for all items is that Dato sets rich-text content.
#### What is the diamond menu bar icon that suddenly appeared?
This is the menu item for the “upcoming event in menu bar” feature. It shows this diamond icon when there are no active events. You can choose to either hide it or show a different icon in the settings.
#### It does not support the video call service I use
I'm happy to add support for more [services](#supported-video-call-services). Just [send me](/feedback?product=Dato&referrer=Website-FAQ) an invitation link (replace a few characters at the end to anonymize it).
The app can also detect the link of any video call service if you correctly add it in the Calendar app:
- Create a new event.
- Paste the video call link into the location field.
- Accept the dropdown suggestion about it being a video call.
If you don't use the Calendar app, you can add the following to the notes field of an event:
```
----( Video Call )----
https://some-video-call-service.com/join/23423
---===---
```
#### How do I add a calendar?
[Add the calendar to the built-in Calendar app](https://support.apple.com/guide/calendar/add-or-delete-calendar-accounts-icl4308d6701/mac) and then enable it in the Dato settings.
#### How can I open meeting links (Google Meet, Zoom, Microsoft Teams, etc.) in a specific browser or browser profile? {#velja}
Check out my [Velja app](/velja). I made it exactly for this purpose. It has built-in support for this without any setup. It can also open links to Zoom and Microsoft Teams directly in their desktop app.
You can even make it open a specific browser or profile only for links clicked in Dato. Create a custom rule in Velja and set the source app as Dato.
#### How can I go back to the current day in the calendar?
Click the month and year on the top left. You can also press the <kbd>Space</kbd> key.
#### I have hidden the toolbar and now I cannot access settings
Press the <kbd>Option</kbd> key to reveal a button to access settings or press <kbd>Command+,</kbd>.
#### How can I add multiple time zones to the menu bar? {#time-zones-menu-bar}
In the Dato settings, go to the “Time Zones” pane, add a time zone, and in the edit window, check “Show in menu bar”. Do the same with the other time zones you want to show in the menu bar. If you already have the time zones added, right-click a time zone, click “Edit”, and then check “Show in menu bar”.
#### Why does the app use a lot of CPU when not in use?
You most likely have enabled showing seconds in the menu bar. Unfortunately, updating the menu bar is quite expensive. This is a problem with macOS and out of my control.
If you don't have seconds enabled, please let me know about the excessive CPU usage.
#### Why does the menu bar hide when I click the Dato menu bar item?
This is a macOS 14 bug and unfortunately not something I can work around.
If you work at Apple → [FB13544993](https://github.com/feedback-assistant/reports/issues/457)
#### Dato is not in sync with Outlook
Dato simply presents events from the macOS calendar system (the builtin Calendar app). It does not do the actual syncing. macOS has known problems with Outlook syncing. [This may help.](https://discussions.apple.com/thread/254365894?sortBy=rank)
#### How can I edit an event in Dato?
Dato does not support editing events. Simply double-click the event in the event list to edit it in the Calendar app.
#### How can I toggle AM/PM for the time?
Dato adheres to what you have set in “System Settings › General › Language and Region”.
#### How can I change the first day of the week?
Dato adheres to what you have set in “System Settings › General › Language and Region”.
#### Can you support natural language input like Fantastical?
I'm hoping to have this done later this year. It's quite a complicated feature.
#### Can you integrate with Notion Calendar (previously Cron)? {#notion-calendar}
The integration is already done, but Notion Calendar has multiple bugs that make it not work properly. We will have to wait for them to fix these bugs.
#### Can you integrate with [Vimcal](https://www.vimcal.com)? {#vimcal}
Vimcal currently lacks integration capabilities. I suggest reaching out to them to request support for a feature like [Fantastical's custom URL scheme](https://flexibits.com/fantastical-ios/help/integration#url-actions).
#### Can you localize the app into my language?
All the date and time output and the calendar adhere to your locale settings. I have no plans to localize the app itself.
#### I added a calendar to the Calendar app but it doesn't show up in the app
You need to enable the calendar in the Dato settings.
#### Can you add support for Google Calendar / Outlook 365 / Exchange?
It's already supported. Just add your calendars to the built-in Calendar app and then enable those calendars in the app settings.
#### Can you support Google Calendars and Outlook directly without going through the Calendar app?
Dato uses macOS's built-in calendaring system, which syncs seamlessly with Google Calendar, Outlook, and other services. This approach ensures all your calendars are managed centrally by macOS, providing a consistent experience across apps. The Calendar app on macOS is just one of the many apps that utilize this system. Adding direct syncing with Google Calendar and Outlook would offer minimal additional benefit but require significant development effort, which would detract from other important improvements.
#### How can I hide the built-in menu bar clock? {#macos11-hide-clock}
It's unfortunately not possible to disable the built-in menu bar clock.
However, you have some options:
1. **(Recommended)** In “System Settings › Control Center › Clock Options”, choose the analog clock and disable showing the date. This gets you the closest to how it was on macOS 10.15 as you can use Dato for both date and time. <img width="258" src="https://user-images.githubusercontent.com/170270/105505537-a5044800-5cfb-11eb-979b-7a0b109f0c93.png"><br>This has the added benefit that while the system clock [shows as disabled](https://user-images.githubusercontent.com/170270/105506021-2c51bb80-5cfc-11eb-84a6-79b62d69d4bc.png) when you enable “Do Not Disturb” (which makes it pretty unreadable), Dato always shows it the same way.
2. Use Dato for showing the date and the built-in clock for the time.
3. Only show an icon for Dato.
I would appreciate it if you could take a moment to [complain to Apple](https://www.apple.com/feedback/macos.html) that they should bring back the ability to disable the built-in menu bar clock. For reference, on macOS 10.15, there's a checkbox called “Show date and time in the menu bar” in “System Preferences › Date & Time › Clock”. This checkbox no longer exists on macOS 11 and later.
I have already [reported it to Apple](https://github.com/feedback-assistant/reports/issues/131), but I have yet to get a reply.
#### What does the “Hide” button on an event do? {#hide-event}
It makes Dato pretend the event does not exist. The event will not be shown in Dato and it will not cause any notifications from Dato. You can unhide events from the `…` menu (at the top-right).
#### What does the “Mute” button on an event do? {#mute-event}
It makes Dato not notify you about the event. This practically means the event will be ignored for:
- Fullscreen notifications
- Upcoming event in the menu bar
- System notifications for video call events
#### How can I customize the menu bar date and time format?
If you just want to toggle a certain component, like date or time, see the “Menu Bar” pane in the Dato settings.
If you want something more custom, go to the “Date & Time Format” text field. You can specify a [datetime pattern](https://nsdateformatter.com).
For example, you could display the full month name, the year, or the day of the year.
#### How can I show the menu bar date and time in [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601) format?
Either change [this system setting](https://apple.stackexchange.com/questions/191445/standard-iso-8601-week-number-in-calendar-app/209340#209340) or go to the “Menu Bar” pane in the Dato settings, and in the “Date & Time Format” text field, write `YYYY-MM-dd HH:mm:ss`.
#### Why does it not show week 53?
You are probably expecting [ISO week-numbering](https://en.wikipedia.org/wiki/ISO_week_date) while having your system set to [Gregorian week numbering](https://en.wikipedia.org/wiki/ISO_week_date#Relation_with_the_Gregorian_calendar). You can change it with [this system setting](https://apple.stackexchange.com/questions/191445/standard-iso-8601-week-number-in-calendar-app/209340#209340).
#### Why does it show the last days of December as week 1?
That is called [ISO week-numbering](https://en.wikipedia.org/wiki/ISO_week_date).
#### It shows the incorrect week number {#incorrect-week-number}
You are probably expecting [ISO week-numbering](https://en.wikipedia.org/wiki/ISO_week_date) while having your system set to [Gregorian week numbering](https://en.wikipedia.org/wiki/ISO_week_date#Relation_with_the_Gregorian_calendar), or the inverse. You can change it with [this system setting](https://apple.stackexchange.com/questions/191445/standard-iso-8601-week-number-in-calendar-app/209340#209340).
#### How can I change the week number to [ISO 8601](https://en.wikipedia.org/wiki/ISO_week_date) format?
Change [this system setting](https://apple.stackexchange.com/questions/191445/standard-iso-8601-week-number-in-calendar-app/209340#209340).
#### How can I open a calendar event in my favorite calendar app (Fantastical, BusyCal, etc.) instead of the built-in Calendar app?
~~Dato uses the system default calendar app. To change the default calendar app, open the Calendar app's settings, and in the “Default calendar app” setting, select the app you want.~~ **Because of a [macOS bug](https://github.com/feedback-assistant/reports/issues/290), this does not work. Instead, drag an event from the Calendar app into Finder, right-click on it, select “Get Info”, select your calendar in the “Open with” field, and click “Change All”. Then relaunch Dato.**
Dato supports opening calendar events directly in Calendar, Fantastical, BusyCal, Outlook, and Google Calendar (web). For other apps, Dato will just open the app.
#### How can I send calendar invites when creating an event?
In the new event window, click the “More Settings” button, and send the invites from the Calendar app.
Built-in support for sending calendar invites directly from Dato is not possible, as Apple does not currently provide this capability for third-party apps.
#### How can I make my calendar refresh more often? {#refresh-interval}
Open the Calendar app's settings, go to the “Accounts” pane, choose the relevant calendar service in the left sidebar, and then change the “Refresh Calendars” setting. Ideally, it should be set to “Push”, but not all services support that, like Google Calendar.
#### How can I accept/decline invites?
Unfortunately, Apple does not allow third-party apps to manage invites. As a workaround, double-click the event in the list to open it in the Calendar app, where you can accept or decline the invite.
#### How can I get system notifications for upcoming events? {#notifications}
Dato does not support this as you can just set it up in the built-in Calendar app. Open the Calendar app's settings, select the “Alerts” pane, and there you can choose when to be notified.
What Dato does support is showing a notification right when an event for a video call starts. The notification includes a button to join the video call directly. You can enable this notification in the Dato settings. You can also enable fullscreen notifications.
#### Can I use the time travel slider to check times on future dates?
Select any date in the calendar and then use the time travel slider to adjust the time for that day.
#### How can I enable fullscreen notifications only at certain times or for certain conditions?
You can use the [Focus Filter](https://support.apple.com/guide/mac-help/mchl613dc43f/mac) that comes with Dato to pause fullscreen notifications when in certain focus modes.
Alternatively, use the built-in Shortcuts app. You can use the `Set Fullscreen Notifications State` action provided by Dato to enable or disable fullscreen notifications. For example, to only enable fullscreen notifications during work hours, you will need to create two shortcuts. One to enable fullscreen notifications and one to disable it. On macOS 26, you can use Shortcuts automations to run them at the correct times. On older macOS versions, you need the [Shortery app](https://apps.apple.com/no/app/shortery/id1594183810?mt=12) for this.
#### How can I enable fullscreen notification only when a certain [Focus mode](https://support.apple.com/guide/mac-help/mchl613dc43f/mac) is active?
Same as the above but trigger the shortcuts when the Focus mode changes.
#### How can I quickly switch between different sets of calendars? {#calendar-sets}
You can use the Shortcuts app to create “calendar sets” that quickly enable or disable specific calendars for different situations (for example, “Work” vs “Personal”).
Use the `Set Calendar Enabled State` action provided by Dato. When no specific calendar is provided, the action applies to all calendars. When no feature is specified, it applies to all features. You can also use `Set Reminder List Enabled State` for reminder lists.
For example, create a “Work Mode” shortcut that disables your personal calendars and enables your work calendars, and a “Personal Mode” shortcut that does the inverse. On macOS 26, you can use Shortcuts automations to trigger them automatically based on time of day or Focus mode. On older macOS versions, you can use Focus Filters or the [Shortery app](https://apps.apple.com/no/app/shortery/id1594183810?mt=12).
#### Can you add support for showing an analog clock like the system clock?
I have no plans to add that, but you can make it work by unchecking the “Time” setting in Dato and keeping the system clock in analog mode.
#### Can you add support for flashing the time separator like the system clock?
I have no plans to add that, but you can make it work by unchecking the “Time” setting in Dato and keeping the system clock.
#### How can I show smart lists from the Reminders app in Dato?
Dato can only show normal lists. macOS does not let third-party apps access smart lists.
#### Can I add links, images, flags, or tags to reminders in the “New Reminder” window?
No, Apple does not expose these features to third-party apps.
#### How can I make the text in Dato be more easily readable?
Try turning off the “Vibrancy” setting. You can also try increasing the text size with the “Larger text” setting.
#### What does the `ⓘ` symbol in the “upcoming event in menu bar” item mean?
It indicates that there are multiple ongoing events, but only one is shown.
#### My Google Calendar does not update in the app {#google-calendar-sync-issue}
The events may not have been [fetched yet by macOS](#refresh-interval).
Or you may have to re-authenticate your Google account. Open the Calendar app's settings, go to the “Accounts” pane, and try to remove and re-add the Google account.
#### Can I show UTC time in the menu bar?
Yes.
1. Open the Dato settings
1. Go to the “Time Zones” pane
1. Click the plus button
1. Write “utc”
1. Select the “UTC” item
1. Click “Add”
1. Enable “Show in menu bar”
1. Click “Save”
#### How can I hide the Dato clock when doing a specific task or at a certain time of the day?
This is a perfect use case for the built-in Shortcuts app. You can use the `Quit App` and `Open App` actions to quit and relaunch Dato whenever needed. For example, you could create a focus shortcut that quits Dato, plays some music, turns off notifications, etc.
To hide the Dato clock at a certain time of the day, you can use Shortcuts automations on macOS 26, or the [Shortery app](https://apps.apple.com/no/app/shortery/id1594183810?mt=12) on older macOS versions.
#### How can I show [day of year](https://nsidc.org/data/user-resources/help-center/day-year-doy-calendar) in the menu bar?
In the “Custom date & time format” setting, write: `D`
[Learn more](https://www.unicode.org/reports/tr35/tr35-dates.html#dfst-day)
#### Can I change the background color of Dato?
No, but you can make it white/black by turning off the “Vibrancy” setting.
#### Can you add more menu bar icons?
I'm happy to consider requests. You can find icons [here](https://developer.apple.com/sf-symbols/) and [here](https://thenounproject.com).
#### The widgets provided by Dato do not show up in the widget picker
This is a known macOS bug. Restarting your computer usually fixes it.
#### The widgets provided by Dato are white or black with no content
Same answer as above.
#### The time zone widget resets each time Dato updates
This is a macOS bug and unfortunately out of my control. Dato simply defines the parameters for the widget, but macOS is the one that shows the configuration screen and saves your choices from there.
#### Can it show the list of events in a separate menu item from the calendar and time zones?
No, but you could use Dato in combination with my [Today](/today) app.
#### How can I show todos from [Things](https://culturedcode.com/things/) in Dato? {#things}
Dato integrates with the Reminders app only. However, you can use the Shortcuts app to sync todos from Things to the Reminders app, which will make Dato show your todos.
[Here is a shortcut](https://www.icloud.com/shortcuts/2b856dd9607f412fb660d009a03d60a8) that does this. Run it and then enable the “Things” reminders list in the Dato settings.
On macOS 26, you can use Shortcuts automations to run the shortcut automatically. On older macOS versions, you can use the [Shortery](https://apps.apple.com/us/app/shortery/id1594183810) app to run the shortcut. Choose the “Application” trigger type and make it trigger when Things becomes “Inactive”. Alternatively, place the shortcut in the menu bar and run it manually.
#### How can I show seconds in the menu bar only when connected to power?
On macOS 26, you can use Shortcuts automations to run a shortcut when connected and disconnected from power. On older macOS versions, you can use the [Shortery](https://apps.apple.com/us/app/shortery/id1594183810) app for this.
- [Show seconds shortcut](https://www.icloud.com/shortcuts/41adf21d1bea44499d5034864687d01d)
- [Hide seconds shortcut](https://www.icloud.com/shortcuts/dcb7b8c4d66740a8a8ba8abae063e661)
#### Can Dato support Focus Filters? {#focus-filters}
Dato has a focus filter for pausing fullscreen notifications. Ideas for other filters welcome.
#### Can I change the chime frequency for the "Hourly Chime" feature?
I don't plan to add more settings to this feature. However, you can achieve this by using the Shortcuts app. Make a shortcut using the “Get Sound” action provided by Dato. On macOS 26, you can use Shortcuts automations to run it at the interval you prefer. On older macOS versions, you can use [Shortery](https://apps.apple.com/us/app/shortery/id1594183810) for this. [Example shortcut.](https://www.icloud.com/shortcuts/72e44ca37e024b8ab016bd827557f00f)
#### How can I transfer my settings from the App Store version to the Setapp version?
Run this command in the Terminal app:
```sh
defaults export com.sindresorhus.Dato - | defaults import com.sindresorhus.Dato-setapp -
```
And to transfer the other way:
```sh
defaults export com.sindresorhus.Dato-setapp - | defaults import com.sindresorhus.Dato -
```
#### How is this different from Fantastical?
Fantastical is a full-blown calendar app, while Dato is a read-only view of your events. Fantastical is a replacement for the built-in Calendar app. You can use both Fantastical and Dato at the same time. Dato even has integration with Fantastical, so you can open events in Dato directly in Fantastical. Fantastical also has a menu bar item, but many people prefer the UI of Dato. Dato also shows time zones and has more customizability for what's shown in the menu bar. Dato can replace the system date/time, for example.
#### How is this different from iStat Menus?
iStat Menus lets you show different kinds of info in the menu bar, like system stats, network speed, etc. Dato is focused on date and time only. Dato also looks better.
#### How is it different from Itsycal?
Dato is not just a calendar app, but also includes menu bar clock replacement, time zones, upcoming event in menu bar, fullscreen notifications, and a lot more. Try both (see the [Dato trial](#trial)) and see for yourself.
#### Why the name “Dato”?
It means “date” in Norwegian. I just wanted a short, unique, and relevant name.
<br>
<br>
#### Dato 5
###### Behavior changes
- **You must now click an event in the list to show event details. Previously you hovered over it.**
- Right-click an event in the list for more actions.
- Double-click an event in the list to open it in the default calendar app.
###### Why are there so many changes?
The latest version of Dato has been rewritten, moving away from its original [system menu](https://developer.apple.com/design/human-interface-guidelines/menus) format — a change partly prompted by macOS 14 breaking various things. This shift has allowed me to implement significant improvements I have envisioned for years. It’s a change for the better, and I encourage you to give it a few weeks to adapt. If you're still unsatisfied after that time, please reach out. I am continuously working to refine and enhance the app, which has grown substantially since its simple beginnings, making the old menu system increasingly impractical for its current complexity.
If you are not ready to move to Dato 5, here is [Dato 4](https://www.dropbox.com/scl/fi/xex1okacdtcctr8nytyu9/Dato-4.7.2-1692797926-1701610613.zip?rlkey=1yrr9r2xdczm35fkpzaoco72u&raw=1), which you can use in the meantime.
##### Some functionality is missing
All existing functionality should be preserved, but some functionality moved into context menus. Simply right-click an event in the event list for more actions. Or right-click an attendee in the event details for more actions.
###### Why does clicking the "upcoming event in menu bar" item now open the main Dato window?
I had a large number of requests that wanted more context for the event (for example, the events coming after it). When you click the "upcoming event in the menu bar" menu item now, it opens the main Dato window, but highlights the clicked event and shows the event details. This lets you easily see what comes after it.
This also enabled the new setting that lets you hide the main Dato menu bar item, since you can now click the "upcoming event in menu bar" item instead.
###### How can I now hide an event from showing up in the menu bar?
Previously, when you clicked the event in the menu bar, you could hide it from the menu bar by clicking “Hide from Menu Bar”. You now need to right-click the menu bar item and click “Mute”.
## Scripting
### Shortcuts
The app comes with support for the Shortcuts app. Look up the app in the Shortcuts app to see what it provides.
### Events
The [distributed notification](/apps/faq#distributed-notifications) `com.sindresorhus.Dato.joinedVideoCall` is emitted when you join a video call from Dato.
## Older Versions
- [5.4.4](https://github.com/sindresorhus/sindresorhus.github.com/releases/download/v1.0.0/Dato.5.4.4.-.macOS.14.zip) for macOS 14
- [5.1.3](https://github.com/sindresorhus/meta/files/14097627/Dato.5.1.3.-.macOS.13.zip) for macOS 13
- [4.3.3](https://github.com/sindresorhus/meta/files/10516478/Dato.4.3.3.-.macOS.12.zip) for macOS 12
- [3.3.8](https://github.com/sindresorhus/meta/files/8935698/Dato.3.3.8.-.macOS.11.zip) for macOS 11
- [2.6.1](https://github.com/sindresorhus/meta/files/6758848/Dato.2.6.1.-.macOS.10.15.zip) for macOS 10.15
- [1.4.9](https://github.com/sindresorhus/meta/files/5360452/Dato.1.14.9.-.Special.last.Mojave.compatible.release.zip) for macOS 10.14
These are free for everyone but they will not run on newer macOS versions.
<script type="application/ld+json" is:inline>
{
"@context": "https://schema.org",
"@type": "SoftwareApplication",
"applicationCategory": "BusinessApplication",
"name": "Dato",
"operatingSystem": "macOS 15",
"aggregateRating": {
"@type": "AggregateRating",
"ratingValue": "4.9",
"ratingCount": "727"
},
"offers": {
"@type": "Offer",
"price": "16.00",
"priceCurrency": "USD"
},
"datePublished": "2019-07-13",
"headline": "Dato — Calendar events and world clocks in your menu bar",
"alternativeHeadline": "Calendar events and world clocks in your menu bar",
"downloadUrl": "https://apps.apple.com/app/id1470584107",
"softwareVersion": "5.5.0",
"screenshot": "https://sindresorhus.com/_astro/screenshot1.IX_7bQOQ.jpg",
"fileSize": "15MB",
"description": "Dato gives you a local clock, date, and multiple world clocks in the menu bar. When you click Dato in the menu bar, you get a menu with a calendar, calendar events, and world clocks. All of this is highly customizable.",
"keywords": "calendar,menu,bar,date,time,zone,world,clock,zoom,meet",
"thumbnailUrl": "https://sindresorhus.com/apps/dato/icon.png",
"author": {
"@type": "Person",
"givenName": "Sindre",
"familyName": "Sorhus",
"jobTitle": "Open-Sourcerer",
"knowsAbout": "Unicorns",
"nationality": "Norway",
"image": "https://sindresorhus.com/assets/sindre-sorhus.jpg",
"url": "https://sindresorhus.com",
"sameAs": "https://github.com/sindresorhus"
}
}
</script>
================================================
FILE: source/content/apps/day-progress.md
================================================
---
title: Day Progress
subtitle: Time remaining today in your menu bar
pubDate: 2023-06-18
platforms:
- macOS
isPaid: true
isMenuBarApp: true
appStoreId: 6450280202
# links:
# 'TestFlight': https://testflight.apple.com/join/mFx764Kp
olderMacOSVersions:
- '13'
- '14'
- '15'
---
Use this as a visual cue to stay motivated and manage time more efficiently.
You can customize your day's start and end times per day, even allowing for a day's end past midnight, such as 2 AM.
You can set up multiple time ranges to run one after another throughout your day - the menu bar shows a single progress at a time. Perfect for tracking different parts of your day like work hours and personal time.
Choose between a progress pie or bar, showing percentage, remaining time, or minutes left.
## Tips
<!-- #### Time presets
You can use the Shortcuts app to make time presets. For example, you can make a shortcut that sets the day range to `13:00 - 18:00` and run it on the days where you want that range, and another shortcut to reset it back to the normal day range. [Example shortcut.](https://www.icloud.com/shortcuts/9636a1f2f0624aa787727afd306ff667)
#### Countdown from 8 hours when you decide
You can use a shortcut to make it count down 8 hours from when you decide. [Example shortcut.](https://www.icloud.com/shortcuts/39c8db30ce9d456bbbbdfcc8ba5eb136)
#### Make the day range be sunrise to sunset for the current location
Run [this shortcut](https://www.icloud.com/shortcuts/830746d544ce471cb1ff70b2f4de0e22) every day using [Shortery](https://apps.apple.com/app/id1594183810) and you will always have the correct sunrise and sunset times. -->
### Reminder about shortcuts
A shortcut can be run from the menu bar, using a global keyboard shortcut, from Spotlight, or from Raycast. You can use Shortcuts automations to make it run automatically, for example, when you change to the work focus. For more automation triggers, you can use [Shortery](https://apps.apple.com/us/app/shortery/id1594183810?mt=12).
### Hide the system clock {#hide-system-clock}
You could use Day Progress as an abstract clock instead of the system clock, to minimize anxiety and distraction from time, enhancing focus and productivity.
Unfortunately, it's not possible to fully hide the built-in menu bar clock. However, you could make it an analog clock, which makes it a lot less visible. In “System Settings › Control Center › Clock Options”, choose the analog clock and disable showing the date.
### Events
The [distributed notification](/apps/faq#distributed-notifications) `com.sindresorhus.Day-Progress.dayEnded` is emitted when a progress finishes.
## Frequently Asked Questions {#faq}
#### The app does not show up in the menu bar
[Try this](/apps/faq#app-not-showing-in-menu-bar)
#### Can you add widgets?
I plan to do that at some point, but not soon.
#### Can you add support for iOS?
I plan to do that at some point, but not soon.
#### Can you support more countdown ranges, like until the end of the week or a certain date?
There are already lots of apps for counting down to a specific date. I wanted to make something more unique. Also, the app name is “Day Progress”.
#### Can you support specifying different day ranges for different days of the week?
You can set up multiple schedules with different time ranges, both for different days and within the same day. Each time range runs its progress one after another in the menu bar. For even more flexibility with scheduling, check out the [tips](#tips) section for automation options using Shortcuts.
#### Does the app provide end-of-day notifications?
At this time, the app doesn't support this. Considering the wide-ranging user preferences of notifications, from system alerts to fullscreen notifications and differing "do not disturb" settings, I've opted to keep the app straightforward and not include notifications for now.
#### Can you add Pomodoro features?
This is outside the scope of the app. Day Progress is meant as a general day progress indicator, not a task timer. There are many dedicated Pomodoro apps available in the App Store.
#### Can it show a progress bar for how much time I have left in my life?
This is out of scope for this app, and there are existing apps for that already.
#### Can you localize the app into my language?
I do not plan to localize the app.
## Older Versions
- [2.0.3](https://www.dropbox.com/scl/fi/mntravypnb9a11938lk28/Day-Progress-2.0.3-macOS-15-1775397609.zip?rlkey=gjl8jl22miwb9csldzdpd8786&raw=1) for macOS 15
- [1.4.0](https://github.com/user-attachments/files/18767518/Day.Progress.1.4.0.-.macOS.14.zip) for macOS 14
- [1.3.0](https://github.com/sindresorhus/meta/files/13979415/Day.Progress.1.3.0.-.macOS.13.zip) for macOS 13
These are free for everyone but they will not run on newer macOS versions.
================================================
FILE: source/content/apps/default-browser.md
================================================
---
title: Default Browser
subtitle: Switch default browser from your menu bar
pubDate: 2025-01-13
platforms:
- macOS
isPaid: true
isMenuBarApp: true
releasesRepo: default-browser-meta
mainLinks:
'Buy': https://sindresorhus.gumroad.com/l/default-browser?wanted=true
requirement: Requires macOS 26 or later
announcement:
text: Save 28% with the Power User Bundle — get 3 power user apps together
url: https://sindresorhus.gumroad.com/l/power-user
urlText: Get the bundle
pressQuotes:
- quote: Sindre Sorhus is a serial indie app developer that specializes in creating niche apps that solve a particularly nagging problem in an often seamless way. Default Browser is one of my favorites.
source: Lifehacker
url: https://lifehacker.com/tech/finally-an-easier-way-to-change-your-default-browser-on-mac
- quote: Works flawlessly! It's exactly what I needed to quickly switch between browsers! Thank you for this fantastic app!
source: Petar Stoyanov
- quote: crashed at launch!
source: John Dorian
olderMacOSVersions:
- '15'
---
Seamlessly switch between browsers directly from your menu bar, keyboard shortcut, Focus mode, or using Shortcuts. Perfect for users who work with multiple browsers.
Unlike similar apps, this one actually changes the system default browser (and without a prompt).
**Features**
- Set the system default browser
- Choose which browsers are shown in the menu
- Hide menu bar icon
- Show the default browser’s icon in the menu bar
- Keyboard shortcut to show the menu
- [Shortcuts app integration](#shortcuts)
- [Focus filter](#focus-filter) to automatically switch browser based on [Focus mode](https://support.apple.com/guide/mac-help/mchl613dc43f/mac#mchl49b73d04)
---
Mentions:
- [Review in MacStories](https://www.macstories.net/reviews/default-browser-a-mac-menu-bar-utility-for-quickly-switching-browsers/)
- [Lifehacker article](https://lifehacker.com/tech/finally-an-easier-way-to-change-your-default-browser-on-mac)
<br>
> [!TIP]
> Switching the default browser is also a feature of my [Supercharge](/supercharge) app.
---
## Tips
### Browser selector
Set a keyboard shortcut to open the menu. Once open, select a browser by pressing its number key or navigate using the arrow keys.
### Launch browser
Hold the Option key and click a browser in the menu to open it, rather than setting it as the default.
### Switch to specific browser with keyboard shortcut {#keyboard-shortcut-set-browser}
Create a [shortcut in the Shortcuts app](https://support.apple.com/guide/shortcuts-mac/intro-to-shortcuts-apdf22b0444c/mac) for each browser using the “Set Default Browser” action, then assign a keyboard shortcut to the shortcut.
### Automatically switch browser based on a trigger {#auto-switch-browser}
The triggers could be: time, location, active app, Wi-Fi network, etc.
For example, set up automatic browser switching between work and personal use through the Shortcuts app. Create two shortcuts using the “Set Default Browser” action - one for each browser. Then use [Shortery](https://apps.apple.com/app/id1594183810) to automatically trigger these shortcuts based on time of day or Wi-Fi network. The Wi-Fi trigger is particularly useful for office workers, as it switches browsers automatically when you connect to your work network.
Use the [Focus filter](#focus-filter) to switch browser based on the active Focus mode.
On macOS 26 and later, you can use the built-in automation triggers in Shortcuts instead of the Shortery app.
## Frequently Asked Questions {#faq}
#### The app does not show up in the menu bar
[Try this](/apps/faq#app-not-showing-in-menu-bar)
You may also have disabled the “Show menu bar icon” setting, which hides the menu bar icon. Launch the app again to show the menu bar icon.
#### Can it support rules for which browser to use for certain URLs? {#rules-support}
Features like rules require the app to intercept and forward URLs by acting as the default browser. This app simply changes the default browser. Check out my [Velja](/velja) app for rules and more.
#### Can it support browser profiles? {#browser-profiles}
Same answer as the above.
With the exception of Orion, which implements profiles as separate apps.
#### How is it different from your [Velja](/velja) app?
Velja works by acting as a browser and forwarding URLs to other browsers, enabling features like rules, interactive browser prompt, desktop app handling, and URL tracking parameter cleaning. This app is simpler - it just changes the system default browser directly.
#### I already own [Supercharge](/supercharge). Does this offer any benefits over its browser switcher feature? {#supercharge}
- Default browser app icon in the menu bar.
- Larger app icons in the menu.
- Keyboard shortcut to show the menu.
- Number key selection for browsers in the menu.
#### Why is this not in the App Store?
Much of the functionality would not be possible in the App Store because of [sandboxing](/apps/faq#macos-sandbox).
#### Can the default browser change based on the macOS desktop Space I’m in? {#macos-spaces}
No. macOS does not expose the active [Space](https://support.apple.com/guide/mac-help/work-in-multiple-spaces-mh14112/mac) to apps, so the app cannot detect or react to it. You can instead automate switching with Focus Filters or Shortcuts (see [tips](#tips)).
## Scripting
### Shortcuts
The app comes with support for the Shortcuts app. Look up the app in the Shortcuts app to see what actions it provides.
For example, you could switch to a certain browser at a [specific time of the day](#auto-switch-browser), or maybe when joining a specific Wi-Fi network. For such triggers, you will also need the [Shortery](https://apps.apple.com/app/id1594183810) app.
### Focus filter
The app includes a [Focus filter](https://support.apple.com/guide/mac-help/mchl613dc43f/mac#mchl49b73d04) to automatically switch the default browser based on the Focus mode. Enable it in “System Settings › Focus”.
### Events
The [distributed notification](/apps/faq#distributed-notifications) `com.sindresorhus.defaultBrowserDidChange` is emitted when the default browser is changed from the app or the Shortcuts action.
## Older Versions
- [1.1.0](https://www.dropbox.com/scl/fi/u9c9gzh7l8jseuga9v2eg/Default-Browser-1.1.0-macOS-15-1771002988.zip?rlkey=37e8ck6g0x3pc3z132olqc8n9&raw=1) for macOS 15
These are free for everyone but they will not run on newer macOS versions.
================================================
FILE: source/content/apps/doodle-draw.md
================================================
---
title: Doodle Draw
subtitle: Quick and easy drawing pad
pubDate: 2024-01-23
platforms:
- iOS
- visionOS
appStoreId: 6476447055
---
Capture your creativity instantly. Ideal for quick sketches, artistic brainstorming, and playful drawing. Simple, intuitive, and fun, turning every touch into doodles.
The app is intentionally simple.
## Frequently Asked Questions {#faq}
#### I can already access these drawing tools in the Notes and Freeform app
This app makes it faster to get started. Just tap the app and start doodling. It also lets you save or erase more quickly. Great for quick brainstorm sessions.
#### How can I undo?
Tap the undo button, shake the device, or swipe left with three fingers.
#### Can I zoom in and out?
There is no zoom functionality. The app is designed for straightforward, full-canvas doodling.
#### Can I draw on an existing image?
This is not supported.
#### Can you support shape detection?
Apple does not let third-party apps use the shape detection functionality, so this is not possible.
#### Why can I only use a single hand when drawing on the visionOS version?
This is a visionOS bug.
#### Can you support macOS?
Unfortunately not possible as the framework used for drawing is too limited on macOS.
#### Why is this free without ads?
I just enjoy making apps. Consider leaving a nice review on the App Store.
#### Can you localize the app into my language?
I don't plan to localize the app.
================================================
FILE: source/content/apps/ds-store-inspector.md
================================================
---
title: DS_Store Inspector
subtitle: Inspect .DS_Store files
pubDate: 2026-01-29
platforms:
- macOS
appStoreId: 6758286374
# olderMacOSVersions:
# - '26'
---
A read-only viewer for Finder metadata stored in [`.DS_Store`](https://en.wikipedia.org/wiki/.DS_Store) files.
`.DS_Store` (Desktop Services Store) files are hidden files macOS creates in every folder you open in Finder. They store folder-specific view preferences like icon positions, window size, and sorting options.
## Frequently Asked Questions {#faq}
#### Why would I want to inspect a `.DS_Store` file?
To understand and debug how Finder presents a folder: sorting, view mode, window size, icon positions, and other hidden state. This is especially useful when investigating odd Finder behavior, auditing metadata left behind in shared folders, repositories, ZIP archives, installers, and designed DMGs, where the `.DS_Store` controls the exact visual layout users see (icon placement, background, window geometry).
#### Can I use this to clean or reset Finder settings?
No. This app is an inspector, not a cleaner. Use it to understand what is stored, then decide separately how to handle it.
#### Why does a .DS_Store file look empty or show little data?
Some folders barely have custom Finder settings, so there’s not much stored. Also, certain records only appear after you change view options (icon positions, sort order, window size, etc).
#### Why are some record types cryptic?
The format is undocumented. Many record types were reverse-engineered, and some Finder internals still use opaque identifiers. If you [send me](/feedback?product=DS_Store%20Inspector&referrer=Website-FAQ) the `.DS_Store` file, I will take a look. Click the button in the “Help” menu in the app.
#### Why does it require macOS 26 or later?
This is just a small, free project I built for fun. Supporting older macOS versions would mean extra testing, compatibility layers, and working around bugs Apple will never fix.
Keeping it macOS 26+ lets me keep the code simple and spend time building things I enjoy instead of maintaining legacy support.
<!-- ## Older Versions
- [1.0.0]() for macOS 26+ -->
## Non-App Store Version
A special version for users that cannot access the App Store. It won't receive automatic updates. I will update it here once a year.
[Download](https://www.dropbox.com/scl/fi/amjh96y5np88k35a29o91/DS_Store-Inspector-1.0.2-1770388348.zip?rlkey=laf8sa8yybe2v1i21oe9ps86d&raw=1) *(1.0.2)*
*Requires macOS 26 or later*
================================================
FILE: source/content/apps/favorites-widget.md
================================================
---
title: Favorites Widget
subtitle: Contacts on your Lock Screen, Home Screen, and desktop
pubDate: 2022-09-12
platforms:
# - macOS # because it crashes because of missing API shim.
- iOS
- visionOS
isPaid: true
appStoreId: 1643660089
hasSentry: true
---
<!-- Call, message, or email your favorite people directly from the Lock Screen, Home Screen, or desktop. -->
Call, message, or email your favorite people directly from the Lock Screen or Home Screen.
You can also open a URL or run a shortcut instead when tapping the widget. This opens up a lot of cool possibilities. Here are [some ideas](https://github.com/bhagyas/app-urls) of what you could open.
<!-- For macOS, it's only available for Apple silicon Macs running macOS 26 or later. -->
## Frequently Asked Questions {#faq}
#### How do I add the widget?
- [iOS](https://support.apple.com/HT207122)
<!-- - [macOS](https://support.apple.com/guide/mac-help/mchl52be5da5/mac) -->
#### The widget does not show up in the widget picker
This is a well-known iOS issue. [Try this.](https://webtrickz.com/third-party-lock-screen-widgets-not-showing-ios-16/)
#### The Lock Screen widget sometimes disappears
Make sure Lock Screen widgets are allowed when locked: “Settings › Face ID & Passcode › Allow Access When Locked › Lock Screen Widgets”. If it’s “off”, iOS may hide the widget until you unlock.
#### Can I call someone by just tapping the widget without the confirmation dialog?
Yes. Enable the “Quick Call” setting in the app.
#### Can the Lock Screen photos be full-colored?
This is unfortunately not possible. iOS enforces that Lock Screen widgets are single-colored.
#### Can you support more actions when tapping a widget?
Sure. I'm happy to consider requests. [Send it here.](https://sindresorhus.com/feedback?product=Favorites%20Widget&referrer=Website-FAQ)
#### Can you make the widget background transparent?
This is not possible.
#### When using the “Run Shortcut” action, why does tapping the widget first open the main app and then the Shortcuts app?
This is because of iOS limitations. A widget can only open its own app when a user taps it. And the only way to run a shortcut is to open the Shortcuts app using a special URL. So when you tap the widget, the widget opens the main app, and the main app then opens the Shortcuts app. It's not a very good user experience, but only Apple can fix this.
If you work at Apple, you know what to do:
- [FB9745173](https://github.com/feedback-assistant/reports/issues/240)
- [FB11516334](https://github.com/feedback-assistant/reports/issues/357)
- [FB11516273](https://github.com/feedback-assistant/reports/issues/356)
<!-- #### Why is this free without ads?
I just enjoy making apps. I earn money on other apps. Consider leaving a nice review on the App Store. -->
#### Can you localize the app into my language?
I don't plan to localize the app.
================================================
FILE: source/content/apps/floating-clock.md
================================================
---
title: Floating Clock
subtitle: The missing clock for Apple Vision
pubDate: 2024-02-17
platforms:
- visionOS
appStoreId: 6477862240
---
Display a digital clock anywhere in your space.
The app is simple by design.
## Frequently Asked Questions {#faq}
#### Can it support showing an analog clock?
No plans to support that.
#### Can it show seconds?
No plans to support that.
#### Can it show the year?
The year is omitted for simplicity; it's generally known.
#### Can you support macOS?
I plan to do this at some point, but not soon.
#### Why is this free without ads?
I just enjoy making apps. Consider leaving a nice review on the App Store.
#### Can you localize the app into my language?
I don't plan to localize the app, but the time and date respects your locale.
================================================
FILE: source/content/apps/folder-peek.md
================================================
---
title: Folder Peek
subtitle: Put folders in your menu bar
pubDate: 2022-04-05
platforms:
- macOS
isPaid: true
isMenuBarApp: true
appStoreId: 1615988943
hasSentry: true
olderMacOSVersions:
- '12'
- '13'
- '14'
- '15'
---
<br>
### Features
- Add multiple folders to the menu bar
- Each folder can be individually customized
- File preview
- View and copy image & video dimensions
- Drag & drop files directly from the menu
- Global keyboard shortcut to show/hide each folder menu (optionally opens at cursor position)
- Open a file or folder in a specific app
- Follows aliases and symlinks
- Shortcuts support
### Guide {#guide}
Folder Peek lets you put one or more folders in the menu bar.
Make sure you read the below tips and FAQ.
## Tips
- Click a file or folder in the menu to open it. Folders open in Finder.
- Click a file while pressing the <kbd>Option</kbd> key to show it in Finder.
- Click the folder title ([the top menu item](https://github.com/sindresorhus/meta/assets/170270/79c4e9c7-8abf-49da-b8fb-3a942017442e)) to open the folder.
- You can drag files directly from the menu. You can also drag the file thumbnail in the file submenu. Press the <kbd>Option</kbd> key while dragging to copy instead of moving.
- Press the <kbd>Option</kbd> key when viewing the file details to copy the path or image/video dimensions.
- You can use the Shortcuts support to show/hide certain folders depending on what project you are working on.
- If you have the menu bar item folders next to each other and you have one folder open, you can press <kbd>Control+Tab</kbd> or <kbd>Shift+Control+Tab</kbd> to switch between them.
- In Settings, you can configure the keyboard shortcut to open the menu at the cursor position instead of at the menu bar icon.
- Press the <kbd>Option</kbd> key while the menu is open to show the `…` menu item at the top if it normally is at the bottom.
- Right-click or <kbd>Option</kbd>-click the menu bar item to open the folder.
- Press the <kbd>Shift</kbd> key while viewing a subfolder to reveal more actions. For example, sort order settings.
- Search: Just start typing when the menu is open to find a file or folder in the menu. This is just the standard menu behavior where you can type to highlight a certain menu item. It's not a full-blown search.
### Links
You can use Folder Peek to access links too. Drag and drop the URL from the Safari address bar into a folder. You will end up with a file with a `.webloc` extension. When you click that file in Folder Peek, it will open in your browser.
### Desktop folder
You could add the “Desktop” folder to Folder Peek and then [hide the desktop icons](https://beebom.com/how-hide-desktop-icons-mac/) for a cleaner look.
## Frequently Asked Questions {#faq}
#### The app does not show up in the menu bar
[Try this](/apps/faq#app-not-showing-in-menu-bar)
#### Why is the app suddenly paid? It used to be free.
While I love making free apps that are available to anyone, the high volume of support requests became unsustainable. After providing the app for free for 4 years with more than 50K downloads, I made the decision to make it paid. This isn't about revenue - it's about managing my time more effectively by reducing the support burden to a sustainable level.
#### Some folders are suddenly missing from the menu bar
When the menu bar has no space left, macOS hides overflowing items. Try quitting some menu bar apps.
#### The menu bar icon is not perfectly vertically centered
This is a macOS bug on non-Retina displays. There is unfortunately not much I can do about this.
#### How can I show specific files and folders from various places? {#show-specific-items}
You can create a folder that contains aliases to the files and folders you want to be included in the menu.
Create a folder to put aliases in and add that folder to the app. Make aliases for the files and folders you want in the menu and move the aliases into the folder you just made.
#### What is an alias?
An [alias](https://support.apple.com/guide/mac-help/create-and-remove-aliases-on-mac-mchlp1046/mac) is a shortcut to an app, file, or folder that you can keep anywhere on your Mac. Right-click an item in Finder and select “Make Alias” to make one.
#### How can I use this as an app launcher? {#app-launcher}
Just add the “Applications” folder to the app. If you want to show only specific apps, follow the first FAQ.
#### How can I show multiple folders at the top level in a single menu? {#show-multiple-folders}
See the “Can I show specific files and folders from various places?” answer.
#### How can I show certain folders in the menu bar depending on what I'm working on? {#faq-shortcuts}
You can create a shortcut in the Shortcuts app using the “Set Folder Visibility” action where you show only certain folders. For example, you could make a shortcut named “Start Work” which hides your personal folders in the menu bar and shows folders for your work projects. On macOS 26, you can use Shortcuts automations to trigger this shortcut at a certain time or any other condition. On older macOS versions, you can use the [Shortery app](https://apps.apple.com/us/app/shortery/id1594183810) for this.
#### How can I drag & drop a file from the menu?
You can drag & drop files directly from the menu. Press the <kbd>Option</kbd> key while dragging to copy instead of moving.
#### How can I copy the file path? {#copy-file-path}
Press the <kbd>Option</kbd> key while viewing a file to reveal a “Copy Path” button.
#### How can I copy the image/video dimensions?
Press the <kbd>Option</kbd> key while viewing an image or video to reveal a “Copy Dimensions” button.
#### How can I change the sort order for a subfolder?
Press the <kbd>Shift</kbd> key while viewing a subfolder to reveal more actions, including a sort order setting.
#### How can I have a menu bar folder with my most recent screenshots?
Make a folder to hold the screenshots and add the folder to the app. Open the Screenshot app, click “Options”, then “Other Location”, and choose the folder you just made. In Folder Peek, open the folder config, change the sort order to “Date Created”, and set “Max Items” to something like 20.
You may also want to [disable the screenshot preview](https://osxdaily.com/2019/08/02/disable-screenshot-thumbnail-preview-mac/) so the screenshot shows up in the screenshot folder right away.
#### How can I add a [Smart Folder](https://support.apple.com/guide/mac-help/create-or-change-a-smart-folder-on-mac-mchlp2804/mac)? {#smart-folder}
A Smart Folder is a special feature in Finder that allows you to create a virtual folder based on specific search criteria. The files within the Smart Folder are not physically stored in one location, but rather are located in different areas of your computer. Unfortunately, it is not possible to add a Smart Folder to Folder Peek as the functionality cannot be replicated.
#### How do I remove a folder from Folder Peek?
Click the menu bar item, go to the first menu bar item (which is named after your folder), go to its submenu, and then select “Remove Folder”.
#### Can I navigate to a folder multiple levels deep and then drop a file into it?
No, that is unfortunately not possible. Folder Peek is built as a system menu, and a menu cannot be kept open if it's not focused. Instead, first, navigate to the nested folder, click to open it in Finder, and then drag & drop the file into the Finder window.
#### Can it auto-mount a network volume when accessing it? {#network-volume}
No, this is not possible because of [sandboxing](/apps/faq#macos-sandbox). To use a network volume in the app, you need to either mount it manually first or use a tool like [AutoMounter](https://pixeleyes.co.nz/automounter/) to keep it always mounted.
#### Can it support adding a tag instead of a folder?
No. This is not planned.
#### The app I want does not show up in the “Open With” menu for a folder {#folder-open-with}
Apps define the types they support and Folder Peek just fetches a list of apps that support opening folders. However, many apps forget to declare support for folders even though they can open them. I would encourage reporting this to the developers of the app you want to open ([example report](https://github.com/microsoft/vscode/issues/146977)). In the meantime, I'm happy to manually add the app to the list if you contact me, but you are expected to also have reported the issue to the app's developers.
The app developer will need to add `public.folder` to `LSItemContentTypes` in their app's Info.plist:
```xml
<key>LSItemContentTypes</key>
<array>
<string>public.folder</string>
</array>
```
#### How can I make folders open in a different app than Finder by default? {#finder-alternative}
Folder Peek opens the default app that handles folders, which is Finder by default.
- **Path Finder:** Enable the “Set as the default file browser” setting in Path Finder.
- **ForkLift:** [Follow this guide.](https://binarynights.com/manual#fileviewer)
For other apps, follow [this guide](https://binarynights.com/manual#fileviewer), but replace `com.binarynights.ForkLift-3` with the bundle identifier of the app you want.
#### How can I hide the `…` menu item?
There is a hidden setting for it. Run the following command in the Terminal app:
```sh
defaults write com.sindresorhus.Folder-Peek showFolderMoreMenu -bool false
```
You can show the `…` menu item again by pressing the <kbd>Option</kbd> key.
#### How is this better than having [folders in the Dock](https://support.apple.com/guide/mac-help/use-folders-in-the-dock-mchl231f08fb/mac)? {#dock-folders}
- Slightly faster access, since most users have the Dock automatically hidden and the menu bar always shown.
- File preview.
- Copy and share a file.
- View and copy image/video dimensions.
- Open a file or folder in a specific app.
- Keep folders on top.
- Sort by when the file was last accessed.
- Show the menu using a custom global keyboard shortcut.
- Limit the number of items shown in the menu.
- Shortcuts support.
#### How is this better than [XMenu](https://apps.apple.com/us/app/xmenu/id419332741)? {#xmenu}
- You can choose any folder and as many as you want, not just a few predefined ones and a single custom folder.
- Each folder can be individually customized.
- Sandboxed app (more secure).
- Custom menu bar icon.
- File preview.
- Copy, share, and drag & drop a file.
- View and copy image/video dimensions.
- Open a file or folder in a specific app.
- Sort files by date created, date modified, date accessed, date added, and kind.
- Show the menu using a custom global keyboard shortcut.
- Limit the number of items shown in the menu.
- Shortcuts support.
#### Can I add shortcuts or scripts to the menu? {#short-run}
The app is for folders only. However, I have an app for exactly this: [Short Run](/short-run), which lets you run shortcuts from the menu bar.
#### How can I export, import, sync, or back up the settings?
[See this guide.](https://github.com/sindresorhus/guides/blob/main/backup-app-settings.md)
#### Can you localize the app into my language?
I don't plan to localize the app.
## Older Versions
- [1.12.0](https://www.dropbox.com/scl/fi/hlyb11lf2m65st8daptme/Folder-Peek-1.12.0-macOS-15-1775931438.zip?rlkey=7bykzpnc4iik0izgibhxx1sxo&raw=1) for macOS 15
- [1.11.5](https://github.com/user-attachments/files/18925258/Folder.Peek.1.11.5.-.macOS.14.zip) for macOS 14
- [1.9.2](https://github.com/sindresorhus/meta/files/13980050/Folder.Peek.1.9.2.-.macOS.13.zip) for macOS 13
- [1.6.1](https://github.com/sindresorhus/meta/files/10901140/Folder.Peek.1.6.1.-.macOS.12.zip) for macOS 12
These are free for everyone but they will not run on newer macOS versions.
================================================
FILE: source/content/apps/gifski.md
================================================
---
title: Gifski
subtitle: Convert videos to high-quality GIFs
pubDate: 2018-02-23
platforms:
- macOS
repoUrl: https://github.com/sindresorhus/Gifski
appStoreId: 1351639930
hasSentry: true
links:
'Older Versions': https://github.com/sindresorhus/Gifski#download
'TestFlight': https://testflight.apple.com/join/iCyHNNIA
olderMacOSVersions:
- '10.13'
- '10.14'
- '10.15'
- '11'
- '12'
- '13'
---
A macOS app for the [gifski encoder](https://gif.ski), which converts videos to GIF animations using [pngquant's](https://pngquant.org) fancy features for efficient cross-frame palettes and temporal dithering. It produces animated GIFs that use thousands of colors per frame.
If you don't have a video, you can try the app out with [this one](https://github.com/sindresorhus/meta/assets/170270/6606c1d2-c0ce-4b7e-9eb8-a3916e601e48).
---
*Help test the next major version of Gifski on [TestFlight](https://testflight.apple.com/join/iCyHNNIA).*
================================================
FILE: source/content/apps/googly-eyes.md
================================================
---
title: Googly Eyes
subtitle: Watchful eyes in your menu bar
pubDate: 2025-03-12
platforms:
- macOS
isMenuBarApp: true
appStoreId: 6743048714
olderMacOSVersions:
- '15'
---
Add playful eyes to your menu bar that follow your cursor and blink when you click. Pure whimsy! 👀
## Frequently Asked Questions {#faq}
#### The app does not show up in the menu bar
[Try this](/apps/faq#app-not-showing-in-menu-bar)
#### Why is it using a lot of CPU?
The app is optimized as much as possible, but macOS is inefficient at updating menu bar items. Also, make sure you know how to [interpret CPU usage](/apps/faq#high-cpu).
#### Does it support multiple screens?
Partly.
The eyes follow your cursor across displays. However, menu bar items on inactive secondary displays are just static macOS clones, so those eyes cannot track independently.
This is a macOS limitation and cannot be worked around.
## Older Versions
- [1.1.4](https://www.dropbox.com/scl/fi/p4ym425ivfp4ex1enlh1l/Googly-Eyes-1.1.4-macOS-15-1774281617.zip?rlkey=7jbf2llhjjielpvde6rcpvp8n&raw=1) for macOS 15+
## Non-App Store Version
A special version for users that cannot access the App Store. It won't receive automatic updates. I will update it here once a year.
[Download](https://www.dropbox.com/scl/fi/t8qoulw2nfo2wbzoekbop/Googly-Eyes-1.2.0-1774281367.zip?rlkey=purr5ntc70na53ndpt06oxcuh&raw=1) *(1.2.0 · macOS 26+)*
<script type="module" is:inline>
// Only the core measurements
const CONSTANTS = {
EYE: {
DIAMETER: 70,
TOP: 94,
LEFT: {
LEFT_EYE: 71,
RIGHT_EYE: 153
}
},
PUPIL: {
SIZE: 20
}
};
// Derived measurements
const EYE_RADIUS = CONSTANTS.EYE.DIAMETER / 2;
// Maximum travel is eye radius minus pupil radius to keep pupil fully inside
const MAX_PUPIL_TRAVEL = EYE_RADIUS - (CONSTANTS.PUPIL.SIZE / 2);
// Replace the image source
const img = document.querySelector('img[src$="icon.png"]');
img.src = '/apps/googly-eyes/icon-no-pupils.png';
// Create and position pupils
const container = document.createElement('div');
container.style.cssText = `
position: relative;
width: ${img.width}px;
height: ${img.height}px;
display: inline-block;
`;
img.parentNode.insertBefore(container, img);
container.appendChild(img);
// Add keyframes for touch devices
const style = document.createElement('style');
style.textContent = `
@keyframes rollEyes {
0% { transform: translate(-50%, -50%) rotate(0deg) translate(${MAX_PUPIL_TRAVEL}px) rotate(0deg); }
25% { transform: translate(-50%, -50%) rotate(90deg) translate(${MAX_PUPIL_TRAVEL}px) rotate(-90deg); }
50% { transform: translate(-50%, -50%) rotate(180deg) translate(${MAX_PUPIL_TRAVEL}px) rotate(-180deg); }
75% { transform: translate(-50%, -50%) rotate(270deg) translate(${MAX_PUPIL_TRAVEL}px) rotate(-270deg); }
100% { transform: translate(-50%, -50%) rotate(360deg) translate(${MAX_PUPIL_TRAVEL}px) rotate(-360deg); }
}
`;
document.head.appendChild(style);
// Debug bounds
const createEyeBound = (left) => {
const eyeBound = document.createElement('div');
eyeBound.style.cssText = `
position: absolute;
width: ${CONSTANTS.EYE.DIAMETER}px;
height: ${CONSTANTS.EYE.DIAMETER}px;
border: 2px solid rgba(255, 0, 0, 0.5);
background: rgba(255, 0, 0, 0.1);
border-radius: 50%;
top: ${CONSTANTS.EYE.TOP}px;
left: ${left}px;
transform: translate(-50%, -50%);
pointer-events: none;
`;
return eyeBound;
};
const leftEyeBound = createEyeBound(CONSTANTS.EYE.LEFT.LEFT_EYE);
const rightEyeBound = createEyeBound(CONSTANTS.EYE.LEFT.RIGHT_EYE);
// Debug.
// container.appendChild(leftEyeBound);
// container.appendChild(rightEyeBound);
const createPupil = (left) => {
const pupil = document.createElement('div');
pupil.style.cssText = `
position: absolute;
width: ${CONSTANTS.PUPIL.SIZE}px;
height: ${CONSTANTS.PUPIL.SIZE}px;
background: black;
border-radius: 50%;
top: ${CONSTANTS.EYE.TOP}px;
left: ${left}px;
transform: translate(-50%, -50%);
`;
return pupil;
};
const leftPupil = createPupil(CONSTANTS.EYE.LEFT.LEFT_EYE);
const rightPupil = createPupil(CONSTANTS.EYE.LEFT.RIGHT_EYE);
container.appendChild(leftPupil);
container.appendChild(rightPupil);
// Check if it's a touch device
const isTouchDevice = ('ontouchstart' in window) || (navigator.maxTouchPoints > 0);
if (isTouchDevice) {
const leftSpeed = 2 + Math.random() * 2;
const rightSpeed = 2 + Math.random() * 2;
style.textContent = `
@keyframes rollLeftEye {
0% { transform: translate(-50%, -50%) rotate(0deg) translate(${MAX_PUPIL_TRAVEL}px) rotate(0deg); }
100% { transform: translate(-50%, -50%) rotate(360deg) translate(${MAX_PUPIL_TRAVEL}px) rotate(-360deg); }
}
@keyframes rollRightEye {
0% { transform: translate(-50%, -50%) rotate(0deg) translate(${MAX_PUPIL_TRAVEL}px) rotate(0deg); }
100% { transform: translate(-50%, -50%) rotate(-360deg) translate(${MAX_PUPIL_TRAVEL}px) rotate(360deg); }
}
`;
leftPupil.style.animation = `rollLeftEye ${leftSpeed}s linear infinite`;
rightPupil.style.animation = `rollRightEye ${rightSpeed}s linear infinite`;
} else {
let isFirstMove = true;
function updatePupils(mouseX, mouseY) {
const rect = container.getBoundingClientRect();
for (const [index, pupil] of [leftPupil, rightPupil].entries()) {
const eyeX = rect.left + (index === 0 ? CONSTANTS.EYE.LEFT.LEFT_EYE : CONSTANTS.EYE.LEFT.RIGHT_EYE);
const eyeY = rect.top + CONSTANTS.EYE.TOP;
// Vector from eye to mouse
let x = mouseX - eyeX;
let y = mouseY - eyeY;
const distance = Math.sqrt(x * x + y * y);
if (distance > MAX_PUPIL_TRAVEL) {
const angle = Math.atan2(y, x);
x = Math.cos(angle) * MAX_PUPIL_TRAVEL;
y = Math.sin(angle) * MAX_PUPIL_TRAVEL;
}
pupil.style.transform = `translate(calc(-50% + ${x}px), calc(-50% + ${y}px))`;
}
}
const centerX = container.getBoundingClientRect().left + (CONSTANTS.EYE.LEFT.LEFT_EYE + CONSTANTS.EYE.LEFT.RIGHT_EYE) / 2;
const centerY = container.getBoundingClientRect().top + CONSTANTS.EYE.TOP;
updatePupils(centerX, centerY);
document.addEventListener('mousemove', (e) => {
if (isFirstMove) {
isFirstMove = false;
for (const pupil of [leftPupil, rightPupil]) {
pupil.style.transition = 'transform 0.3s ease-out';
}
requestAnimationFrame(() => {
requestAnimationFrame(() => {
for (const pupil of [leftPupil, rightPupil]) {
pupil.style.transition = '';
}
});
});
}
updatePupils(e.clientX, e.clientY);
});
}
</script>
================================================
FILE: source/content/apps/heic-converter.md
================================================
---
title: HEIC Converter
subtitle: Convert HEIC images to JPEG or PNG
pubDate: 2017-10-09
platforms:
- macOS
appStoreId: 1294126402
hasSentry: true
olderMacOSVersions:
- '10.13'
- '10.14'
- '10.15'
- '11'
- '12'
- '13'
- '14'
---
HEIC Converter is a macOS app that makes it easy to quickly convert images in the [HEIC](https://www.macworld.co.uk/feature/iphone/what-is-heic-3660408/) format to JPEG or PNG. HEIC is Apple's new default image format since iOS 11, replacing JPEG. HEIC uses more advanced and modern compression methods to achieve much smaller file sizes with the same visual quality. Unfortunately, HEIC is a very new format and not yet supported outside of iOS and macOS. This app makes it possible to share your HEIC images on the web or with non-Apple users.
If you don't have any HEIC images, you can try the app out with [this one](/apps/heic-converter/heic-example.heic).
## Frequently Asked Questions {#faq}
#### Does it preserve 10-bit depth?
No. JPEG only supports 8-bit. PNG supports 8-bit and 16-bit, but macOS doesn't h
gitextract_c4ya43z6/ ├── .editorconfig ├── .gitattributes ├── .github/ │ └── workflows/ │ └── deploy.yml ├── .gitignore ├── AGENTS.md ├── astro.config.js ├── license ├── note-to-self.md ├── package.json ├── public/ │ ├── CNAME │ ├── apps/ │ │ └── heic-converter/ │ │ └── heic-example.heic │ ├── feedback/ │ │ └── index.html │ └── keybase.txt ├── readme.md ├── source/ │ ├── components/ │ │ ├── apps/ │ │ │ ├── AppsByPlatform.astro │ │ │ ├── AppsCategory.astro │ │ │ └── AppsList.astro │ │ ├── blog/ │ │ │ ├── List.astro │ │ │ ├── ListItem.astro │ │ │ ├── Pagination.astro │ │ │ ├── Post.astro │ │ │ └── Tags.astro │ │ ├── core/ │ │ │ ├── MetaTags.astro │ │ │ └── ToggleMenu.astro │ │ └── widgets/ │ │ ├── Announcement.astro │ │ ├── Footer.astro │ │ ├── Header.astro │ │ ├── HeaderLink.astro │ │ ├── OverflowMenu.astro │ │ ├── PressQuotes.astro │ │ └── RelatedApps.astro │ ├── config.mjs │ ├── content/ │ │ ├── apps/ │ │ │ ├── actions.md │ │ │ ├── ai-actions.md │ │ │ ├── aiko.md │ │ │ ├── amazing-ai.md │ │ │ ├── any-text.md │ │ │ ├── app-buddy.md │ │ │ ├── ask-ai.md │ │ │ ├── battery-indicator.md │ │ │ ├── black-out.md │ │ │ ├── blear.md │ │ │ ├── camera-preview.md │ │ │ ├── caprine.md │ │ │ ├── command-x.md │ │ │ ├── dato.md │ │ │ ├── day-progress.md │ │ │ ├── default-browser.md │ │ │ ├── doodle-draw.md │ │ │ ├── ds-store-inspector.md │ │ │ ├── favorites-widget.md │ │ │ ├── floating-clock.md │ │ │ ├── folder-peek.md │ │ │ ├── gifski.md │ │ │ ├── googly-eyes.md │ │ │ ├── heic-converter.md │ │ │ ├── hyperduck.md │ │ │ ├── icon-preview.md │ │ │ ├── imago.md │ │ │ ├── jiffy.md │ │ │ ├── lungo.md │ │ │ ├── memo-widget.md │ │ │ ├── menu-bar-calendar.md │ │ │ ├── menu-bar-spacing.md │ │ │ ├── menu-drop.md │ │ │ ├── one-task.md │ │ │ ├── one-thing.md │ │ │ ├── online-check.md │ │ │ ├── pandan.md │ │ │ ├── pasteboard-viewer.md │ │ │ ├── photo-widget.md │ │ │ ├── plain-text-editor.md │ │ │ ├── plash.md │ │ │ ├── pure-paste.md │ │ │ ├── quick-launch.md │ │ │ ├── quickgpt.md │ │ │ ├── randa.md │ │ │ ├── recordia.md │ │ │ ├── scratchpad.md │ │ │ ├── second-clock.md │ │ │ ├── shareful.md │ │ │ ├── short-run.md │ │ │ ├── shortcutie.md │ │ │ ├── simple-color-palette.md │ │ │ ├── spaced.md │ │ │ ├── speediness.md │ │ │ ├── supercharge.md │ │ │ ├── system-color-picker.md │ │ │ ├── text-lens.md │ │ │ ├── today.md │ │ │ ├── touch-bar-simulator.md │ │ │ ├── utc-time.md │ │ │ ├── velja.md │ │ │ ├── week-number.md │ │ │ └── zone-bar.md │ │ └── blog/ │ │ ├── empathy-in-open-source.md │ │ ├── goodbye-nodejs-buffer.md │ │ ├── issue-bumping.md │ │ ├── micro-benchmark-fallacy.md │ │ ├── shortcutie-setapp.md │ │ └── small-focused-modules.md │ ├── content.config.ts │ ├── data/ │ │ └── apps-extra.json │ ├── env.d.ts │ ├── layouts/ │ │ ├── BaseLayout.astro │ │ ├── BlogLayout.astro │ │ ├── MarkdownLayout.astro │ │ ├── PageLayout.astro │ │ └── SimplePageLayout.astro │ ├── pages/ │ │ ├── 404.astro │ │ ├── [...apps]/ │ │ │ ├── [slug]/ │ │ │ │ ├── privacy-policy.astro │ │ │ │ ├── release-notes.astro │ │ │ │ └── rss.xml.js │ │ │ └── [slug].astro │ │ ├── [...blog]/ │ │ │ ├── [...page].astro │ │ │ ├── [slug].astro │ │ │ └── _[tag]/ │ │ │ └── [...page].astro │ │ ├── _apps-extra.astro │ │ ├── _apps-heatmap.astro │ │ ├── about.md │ │ ├── apps/ │ │ │ ├── affiliates.md │ │ │ ├── archived.astro │ │ │ ├── discounts.md │ │ │ ├── faq.md │ │ │ ├── free.astro │ │ │ ├── ios.astro │ │ │ ├── macos.astro │ │ │ ├── menu-bar.astro │ │ │ ├── older-versions.astro │ │ │ ├── paid.astro │ │ │ ├── random.astro │ │ │ ├── setapp.astro │ │ │ ├── shortcuts.astro │ │ │ ├── terms.md │ │ │ ├── visionos.astro │ │ │ └── watchos.astro │ │ ├── apps.astro │ │ ├── contact.astro │ │ ├── donate.md │ │ ├── feedback.astro │ │ ├── feeds.astro │ │ ├── index.astro │ │ ├── og/ │ │ │ └── [slug].png.js │ │ ├── repos.md │ │ ├── rss-apps.xml.js │ │ ├── rss-repos.xml.js │ │ ├── rss.xml.js │ │ ├── supporters.md │ │ └── tiny-apps.md │ └── utils/ │ ├── apps.js │ ├── permalinks.js │ ├── posts.js │ ├── rehype-kbd-separator.js │ ├── remark-heading-meta.js │ ├── remark-inject-feedback-faq.js │ ├── remark-inject-feedback-faq.test.js │ └── utils.js ├── styles/ │ └── global.css └── tsconfig.json
SYMBOL INDEX (20 symbols across 8 files)
FILE: source/config.mjs
constant SITE (line 1) | const SITE = {
FILE: source/pages/[...apps]/[slug]/rss.xml.js
function GET (line 7) | async function GET(context) {
FILE: source/pages/og/[slug].png.js
constant TEMPLATE_VERSION (line 10) | const TEMPLATE_VERSION = '1';
function generateOgImage (line 30) | async function generateOgImage(app) {
function getStaticPaths (line 159) | async function getStaticPaths() {
function GET (line 170) | async function GET({props}) {
FILE: source/utils/permalinks.js
constant APPS_BASE (line 24) | const APPS_BASE = 'apps';
constant BLOG_BASE (line 25) | const BLOG_BASE = 'blog';
constant POST_BASE (line 26) | const POST_BASE = 'blog';
constant TAG_BASE (line 27) | const TAG_BASE = 'blog/tag';
FILE: source/utils/rehype-kbd-separator.js
function walk (line 21) | function walk(node) {
function rehypeKbdSeparator (line 57) | function rehypeKbdSeparator() {
FILE: source/utils/remark-heading-meta.js
function findPrecedingHeading (line 26) | function findPrecedingHeading(children, fromIndex) {
function remarkHeadingMeta (line 42) | function remarkHeadingMeta() {
FILE: source/utils/remark-inject-feedback-faq.js
function remarkInjectFeedbackFaq (line 9) | function remarkInjectFeedbackFaq() {
FILE: source/utils/utils.js
function getReleaseNotesStaticPaths (line 10) | async function getReleaseNotesStaticPaths() {
function cleanPathname (line 30) | function cleanPathname(pathname) {
function githubApi (line 34) | async function githubApi(path) {
function fetchGitHubReleases (line 53) | async function fetchGitHubReleases(repo) {
function fetchFilteredReleases (line 57) | async function fetchFilteredReleases(repo) {
Condensed preview — 159 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (809K chars).
[
{
"path": ".editorconfig",
"chars": 175,
"preview": "root = true\n\n[*]\nindent_style = tab\nend_of_line = lf\ncharset = utf-8\ntrim_trailing_whitespace = true\ninsert_final_newlin"
},
{
"path": ".gitattributes",
"chars": 19,
"preview": "* text=auto eol=lf\n"
},
{
"path": ".github/workflows/deploy.yml",
"chars": 621,
"preview": "name: Deploy\n\non:\n push:\n branches:\n - main\n workflow_dispatch:\n schedule:\n - cron: '0 0 * * *' # Runs eve"
},
{
"path": ".gitignore",
"chars": 90,
"preview": "node_modules\nyarn.lock\n/dist\n/.output\n*.sublime-project\n*.sublime-workspace\n.astro\n.cache\n"
},
{
"path": "AGENTS.md",
"chars": 3240,
"preview": "# Codebase Notes\n\n## FAQ Suggestions on /feedback\n\nThe feedback page shows relevant FAQ links as the user types their me"
},
{
"path": "astro.config.js",
"chars": 4016,
"preview": "import process from 'node:process';\nimport fs from 'node:fs';\nimport https from 'node:https';\nimport tls from 'node:tls'"
},
{
"path": "license",
"chars": 1117,
"preview": "MIT License\n\nCopyright (c) Sindre Sorhus <sindresorhus@gmail.com> (https://sindresorhus.com)\n\nPermission is hereby grant"
},
{
"path": "note-to-self.md",
"chars": 58,
"preview": "# Note to self\n\n- Use `.not-prose` to avoid prose styles.\n"
},
{
"path": "package.json",
"chars": 1832,
"preview": "{\n\t\"private\": true,\n\t\"type\": \"module\",\n\t\"engines\": {\n\t\t\"node\": \">=22\"\n\t},\n\t\"scripts\": {\n\t\t\"dev\": \"astro dev\",\n\t\t\"start\":"
},
{
"path": "public/CNAME",
"chars": 17,
"preview": "sindresorhus.com\n"
},
{
"path": "public/feedback/index.html",
"chars": 513,
"preview": "<!doctype html>\n<html lang=\"en\">\n\t<meta charset=\"utf-8\">\n\t<title>Redirecting…</title>\n\t<link rel=\"canonical\" href=\"https"
},
{
"path": "public/keybase.txt",
"chars": 3012,
"preview": "==================================================================\nhttps://keybase.io/sindresorhus\n---------------------"
},
{
"path": "readme.md",
"chars": 158,
"preview": "# [sindresorhus.com](https://sindresorhus.com)\n\n> Personal website of Sindre Sorhus\n\n*The website targets the latest ver"
},
{
"path": "source/components/apps/AppsByPlatform.astro",
"chars": 802,
"preview": "---\n// Group and render apps by platform with subsections.\nconst {apps = []} = Astro.props;\n\n// Default order for platfo"
},
{
"path": "source/components/apps/AppsCategory.astro",
"chars": 1640,
"preview": "---\nimport {markdown} from '@astropub/md';\nimport {SITE} from '~/config.mjs';\nimport Layout from '~/layouts/SimplePageLa"
},
{
"path": "source/components/apps/AppsList.astro",
"chars": 262,
"preview": "---\n// Renders a simple list of apps as links with subtitles.\nconst {apps = []} = Astro.props;\n---\n\n<ul>\n\t{apps.map(app "
},
{
"path": "source/components/blog/List.astro",
"chars": 200,
"preview": "---\nimport Item from '~/components/blog/ListItem.astro';\n\nconst {posts} = Astro.props;\n---\n\n<ul>\n\t{\n\t\tposts.map(post => "
},
{
"path": "source/components/blog/ListItem.astro",
"chars": 1233,
"preview": "---\n/// import PostTags from '~/components/blog/Tags.astro';\nimport {getFormattedDate} from '~/utils/utils.js';\n\nconst {"
},
{
"path": "source/components/blog/Pagination.astro",
"chars": 1035,
"preview": "---\nimport {Icon} from 'astro-iconify';\n\nconst {\n\tprevUrl,\n\tnextUrl,\n\tprevText: previousText = 'Newer posts',\n\tnextText "
},
{
"path": "source/components/blog/Post.astro",
"chars": 1753,
"preview": "---\n/// import PostTags from '~/components/blog/Tags.astro';\nimport {getFormattedDate} from '~/utils/utils.js';\nimport {"
},
{
"path": "source/components/blog/Tags.astro",
"chars": 370,
"preview": "---\nimport {getPermalink} from '~/utils/permalinks.js';\n\nconst {\n\ttags,\n\tclass: className = 'text-sm',\n} = Astro.props;\n"
},
{
"path": "source/components/core/MetaTags.astro",
"chars": 3304,
"preview": "---\n/// import {ClientRouter} from 'astro:transitions';\nimport {SEO} from 'astro-seo';\nimport {SITE} from '~/config.mjs'"
},
{
"path": "source/components/core/ToggleMenu.astro",
"chars": 605,
"preview": "<label for=\"menu-toggle\" class=\"ml-1.5 text-gray-500 dark:text-gray-400 hover:bg-gray-100 dark:hover:bg-gray-800 focus:o"
},
{
"path": "source/components/widgets/Announcement.astro",
"chars": 1863,
"preview": "---\nimport {Icon} from 'astro-iconify';\nimport MarkdownIt from 'markdown-it';\n\nconst {text, url, urlText = 'Learn more'}"
},
{
"path": "source/components/widgets/Footer.astro",
"chars": 1883,
"preview": "---\nimport {Icon} from 'astro-iconify';\nimport {iconLinkCSS} from '~/utils/utils.js';\n---\n\n<footer class=\"border-t borde"
},
{
"path": "source/components/widgets/Header.astro",
"chars": 2570,
"preview": "---\nimport {Icon} from 'astro-iconify';\nimport HeaderLink from './HeaderLink.astro';\nimport ToggleMenu from '~/component"
},
{
"path": "source/components/widgets/HeaderLink.astro",
"chars": 664,
"preview": "---\nimport {cleanPathname} from '~/utils/utils.js';\n\nconst {href, class: className, ...properties} = Astro.props;\n\nconst"
},
{
"path": "source/components/widgets/OverflowMenu.astro",
"chars": 1241,
"preview": "---\nimport {Icon} from 'astro-iconify';\n\nexport type OverflowItemProps = {\n\ttitle: string;\n\turl: string;\n};\n\nexport type"
},
{
"path": "source/components/widgets/PressQuotes.astro",
"chars": 1627,
"preview": "---\nconst {quotes} = Astro.props;\nconst isOdd = quotes.length % 2 === 1;\n---\n\n<aside class=\"mx-auto px-6 max-w-3xl mt-28"
},
{
"path": "source/components/widgets/RelatedApps.astro",
"chars": 1542,
"preview": "---\nimport {shufflingArray} from '~/utils/utils.js';\n\nconst {currentApp, allApps} = Astro.props;\n\nconst candidates = all"
},
{
"path": "source/config.mjs",
"chars": 213,
"preview": "export const SITE = {\n\tname: 'Sindre Sorhus',\n\torigin: 'https://sindresorhus.com',\n\tbasePathname: '/',\n\ttitle: 'Sindre S"
},
{
"path": "source/content/apps/actions.md",
"chars": 16743,
"preview": "---\ntitle: Actions\nsubtitle: Additional actions for the Shortcuts app\npubDate: 2021-10-28\nplatforms:\n - macOS\n - iOS\n "
},
{
"path": "source/content/apps/ai-actions.md",
"chars": 5504,
"preview": "---\ntitle: AI Actions\nsubtitle: AI actions for the Shortcuts app\npubDate: 2023-09-26\nplatforms:\n - macOS\n - iOS\n - vi"
},
{
"path": "source/content/apps/aiko.md",
"chars": 19028,
"preview": "---\ntitle: Aiko\nsubtitle: AI-powered audio transcription\npubDate: 2023-03-03\nplatforms:\n - macOS\n - iOS\n - visionOS\ni"
},
{
"path": "source/content/apps/amazing-ai.md",
"chars": 6385,
"preview": "---\ntitle: Amazing AI\nsubtitle: Generate images from text using Stable Diffusion\npubDate: 2022-12-21\nplatforms:\n - macO"
},
{
"path": "source/content/apps/any-text.md",
"chars": 7462,
"preview": "---\ntitle: Any Text\nsubtitle: Put text on your Lock Screen, Home Screen, and desktop\npubDate: 2022-09-12\nplatforms:\n - "
},
{
"path": "source/content/apps/app-buddy.md",
"chars": 1422,
"preview": "---\ntitle: App Buddy\nsubtitle: Helper for my apps\npubDate: 2024-10-20\nplatforms:\n - macOS\nhasSentry: true\nreleasesRepo:"
},
{
"path": "source/content/apps/ask-ai.md",
"chars": 2665,
"preview": "---\ntitle: Ask AI\nsubtitle: Use ChatGPT right on your watch\npubDate: 2023-03-12\nplatforms:\n - watchOS\nappStoreId: 64461"
},
{
"path": "source/content/apps/battery-indicator.md",
"chars": 3917,
"preview": "---\ntitle: Battery Indicator\nsubtitle: Remaining battery time in your menu bar\npubDate: 2017-02-18\nplatforms:\n - macOS\n"
},
{
"path": "source/content/apps/black-out.md",
"chars": 2247,
"preview": "---\ntitle: Black Out\nsubtitle: Hide sensitive parts of an image\npubDate: 2017-12-01\nplatforms:\n - macOS\nisPaid: true\nap"
},
{
"path": "source/content/apps/blear.md",
"chars": 305,
"preview": "---\ntitle: Blear\nsubtitle: Transform photos into blurry wallpapers\npubDate: 2015-06-09\nplatforms:\n - iOS\nrepoUrl: https"
},
{
"path": "source/content/apps/camera-preview.md",
"chars": 3363,
"preview": "---\ntitle: Camera Preview\nsubtitle: Preview your webcam and take photos\npubDate: 2023-05-20\nplatforms:\n - macOS\nisPaid:"
},
{
"path": "source/content/apps/caprine.md",
"chars": 286,
"preview": "---\nisUnlisted: true\ntitle: Caprine\nsubtitle: Elegant Facebook Messenger desktop app\npubDate: 2015-09-16\nplatforms:\n - "
},
{
"path": "source/content/apps/command-x.md",
"chars": 6586,
"preview": "---\ntitle: Command X\nsubtitle: Cut and paste files in Finder\npubDate: 2023-04-30\nplatforms:\n - macOS\nisPaid: true\nisMen"
},
{
"path": "source/content/apps/dato.md",
"chars": 39618,
"preview": "---\ntitle: Dato\nsubtitle: Menu bar calendar and world clocks, plus fullscreen meeting notifications\npubDate: 2019-07-13\n"
},
{
"path": "source/content/apps/day-progress.md",
"chars": 4846,
"preview": "---\ntitle: Day Progress\nsubtitle: Time remaining today in your menu bar\npubDate: 2023-06-18\nplatforms:\n - macOS\nisPaid:"
},
{
"path": "source/content/apps/default-browser.md",
"chars": 6474,
"preview": "---\ntitle: Default Browser\nsubtitle: Switch default browser from your menu bar\npubDate: 2025-01-13\nplatforms:\n - macOS\n"
},
{
"path": "source/content/apps/doodle-draw.md",
"chars": 1457,
"preview": "---\ntitle: Doodle Draw\nsubtitle: Quick and easy drawing pad\npubDate: 2024-01-23\nplatforms:\n - iOS\n - visionOS\nappStore"
},
{
"path": "source/content/apps/ds-store-inspector.md",
"chars": 2516,
"preview": "---\ntitle: DS_Store Inspector\nsubtitle: Inspect .DS_Store files\npubDate: 2026-01-29\nplatforms:\n - macOS\nappStoreId: 675"
},
{
"path": "source/content/apps/favorites-widget.md",
"chars": 2894,
"preview": "---\ntitle: Favorites Widget\nsubtitle: Contacts on your Lock Screen, Home Screen, and desktop\npubDate: 2022-09-12\nplatfor"
},
{
"path": "source/content/apps/floating-clock.md",
"chars": 791,
"preview": "---\ntitle: Floating Clock\nsubtitle: The missing clock for Apple Vision\npubDate: 2024-02-17\nplatforms:\n - visionOS\nappSt"
},
{
"path": "source/content/apps/folder-peek.md",
"chars": 11767,
"preview": "---\ntitle: Folder Peek\nsubtitle: Put folders in your menu bar\npubDate: 2022-04-05\nplatforms:\n - macOS\nisPaid: true\nisMe"
},
{
"path": "source/content/apps/gifski.md",
"chars": 960,
"preview": "---\ntitle: Gifski\nsubtitle: Convert videos to high-quality GIFs\npubDate: 2018-02-23\nplatforms:\n - macOS\nrepoUrl: https:"
},
{
"path": "source/content/apps/googly-eyes.md",
"chars": 6471,
"preview": "---\ntitle: Googly Eyes\nsubtitle: Watchful eyes in your menu bar\npubDate: 2025-03-12\nplatforms:\n - macOS\nisMenuBarApp: t"
},
{
"path": "source/content/apps/heic-converter.md",
"chars": 3516,
"preview": "---\ntitle: HEIC Converter\nsubtitle: Convert HEIC images to JPEG or PNG\npubDate: 2017-10-09\nplatforms:\n - macOS\nappStore"
},
{
"path": "source/content/apps/hyperduck.md",
"chars": 12384,
"preview": "---\ntitle: Hyperduck\nsubtitle: Send links from your iOS & visionOS devices to your Mac\npubDate: 2023-01-27\nplatforms:\n "
},
{
"path": "source/content/apps/icon-preview.md",
"chars": 3114,
"preview": "---\ntitle: Icon Preview\nsubtitle: Preview your app icon and menu bar icon\npubDate: 2024-04-22\nplatforms:\n - macOS\nisMen"
},
{
"path": "source/content/apps/imago.md",
"chars": 4743,
"preview": "---\ntitle: Imago\nsubtitle: Generate images from text using Flux 2\npubDate: 2026-03-22\nplatforms:\n - macOS\nappStoreId: 6"
},
{
"path": "source/content/apps/jiffy.md",
"chars": 3026,
"preview": "---\nisArchived: true\ntitle: Jiffy\nsubtitle: Discover & share the best GIFs\npubDate: 2020-03-25\nplatforms:\n - macOS\nisMe"
},
{
"path": "source/content/apps/lungo.md",
"chars": 9553,
"preview": "---\ntitle: Lungo\nsubtitle: Prevent your Mac from going to sleep\npubDate: 2017-07-26\nplatforms:\n - macOS\nisPaid: true\nis"
},
{
"path": "source/content/apps/memo-widget.md",
"chars": 3810,
"preview": "---\ntitle: Memo Widget\nsubtitle: Sticky notes on your Home Screen, Lock Screen, and desktop\npubDate: 2023-12-16\nplatform"
},
{
"path": "source/content/apps/menu-bar-calendar.md",
"chars": 5138,
"preview": "---\ntitle: Menu Bar Calendar\nsubtitle: A monthly calendar, one click away\npubDate: 2023-08-31\nplatforms:\n - macOS\nisMen"
},
{
"path": "source/content/apps/menu-bar-spacing.md",
"chars": 3667,
"preview": "---\ntitle: Menu Bar Spacing\nsubtitle: Customize the gap between menu bar items\npubDate: 2024-07-09\nplatforms:\n - macOS\n"
},
{
"path": "source/content/apps/menu-drop.md",
"chars": 2529,
"preview": "---\ntitle: Menu Drop\nsubtitle: Quick AirDrop sharing in your menu bar\npubDate: 2025-10-17\nplatforms:\n - macOS\nisMenuBar"
},
{
"path": "source/content/apps/one-task.md",
"chars": 5101,
"preview": "---\ntitle: One Task\nsubtitle: Conquer one task at a time\npubDate: 2023-09-19\nisPaid: true\nappStoreId: 6465745322\nplatfor"
},
{
"path": "source/content/apps/one-thing.md",
"chars": 9021,
"preview": "---\ntitle: One Thing\nsubtitle: Put a single task or goal in your menu bar\npubDate: 2022-01-12\nplatforms:\n - macOS\nisMen"
},
{
"path": "source/content/apps/online-check.md",
"chars": 3200,
"preview": "---\ntitle: Online Check\nsubtitle: Online status in your menu bar\npubDate: 2024-06-23\nplatforms:\n - macOS\nisMenuBarApp: "
},
{
"path": "source/content/apps/pandan.md",
"chars": 6605,
"preview": "---\ntitle: Pandan\nsubtitle: Time awareness in your menu bar\npubDate: 2021-05-31\nplatforms:\n - macOS\nisMenuBarApp: true\n"
},
{
"path": "source/content/apps/pasteboard-viewer.md",
"chars": 381,
"preview": "---\ntitle: Pasteboard Viewer\nsubtitle: Inspect the system pasteboards\npubDate: 2020-02-18\nplatforms:\n - macOS\n - iOS\n "
},
{
"path": "source/content/apps/photo-widget.md",
"chars": 4725,
"preview": "---\ntitle: Photo Widget\nsubtitle: Photos on your home screen and desktop\npubDate: 2020-09-22\nplatforms:\n - macOS\n - iO"
},
{
"path": "source/content/apps/plain-text-editor.md",
"chars": 5188,
"preview": "---\ntitle: Plain Text Editor\nsubtitle: Simple distraction-free notepad\npubDate: 2022-10-25\nplatforms:\n - macOS\n - iOS\n"
},
{
"path": "source/content/apps/plash.md",
"chars": 9411,
"preview": "---\ntitle: Plash\nsubtitle: Make any website your desktop wallpaper\npubDate: 2020-01-09\nplatforms:\n - macOS\nisMenuBarApp"
},
{
"path": "source/content/apps/pure-paste.md",
"chars": 15287,
"preview": "---\ntitle: Pure Paste\nsubtitle: Paste as plain text by default\npubDate: 2022-03-02\nplatforms:\n - macOS\nisPaid: true\nisM"
},
{
"path": "source/content/apps/quick-launch.md",
"chars": 2893,
"preview": "---\ntitle: Quick Launch\nsubtitle: Open websites, apps, and shortcuts from your Lock Screen\npubDate: 2022-09-28\nplatforms"
},
{
"path": "source/content/apps/quickgpt.md",
"chars": 2962,
"preview": "---\ntitle: QuickGPT\nsubtitle: Easy access to ChatGPT\npubDate: 2023-04-12\nplatforms:\n - macOS\nisPaid: true\nreleasesRepo:"
},
{
"path": "source/content/apps/randa.md",
"chars": 1540,
"preview": "---\ntitle: Randa\nsubtitle: Generate random numbers\npubDate: 2022-12-17\nplatforms:\n - macOS\n - iOS\n - watchOS\n - visi"
},
{
"path": "source/content/apps/recordia.md",
"chars": 3212,
"preview": "---\ntitle: Recordia\nsubtitle: Quickly record audio\npubDate: 2020-09-02\nplatforms:\n - macOS\nisMenuBarApp: true\nappStoreI"
},
{
"path": "source/content/apps/scratchpad.md",
"chars": 11382,
"preview": "---\ntitle: Scratchpad\nsubtitle: Quick notes, always available\npubDate: 2024-08-30\nplatforms:\n - macOS\n - iOS\n - visio"
},
{
"path": "source/content/apps/second-clock.md",
"chars": 3722,
"preview": "---\ntitle: Second Clock\nsubtitle: Show a second clock for a different time zone in your menu bar\npubDate: 2024-01-04\npla"
},
{
"path": "source/content/apps/shareful.md",
"chars": 2906,
"preview": "---\ntitle: Shareful\nsubtitle: Give the macOS share menu superpowers\npubDate: 2020-09-08\nplatforms:\n - macOS\nappStoreId:"
},
{
"path": "source/content/apps/short-run.md",
"chars": 8455,
"preview": "---\ntitle: Short Run\nsubtitle: Run shortcuts from your menu bar\npubDate: 2025-08-14\nplatforms:\n - macOS\nisPaid: true\nis"
},
{
"path": "source/content/apps/shortcutie.md",
"chars": 19804,
"preview": "---\ntitle: Shortcutie\nsubtitle: Power up the Shortcuts app on Mac\npubDate: 2025-02-11\nplatforms:\n - macOS\nisPaid: true\n"
},
{
"path": "source/content/apps/simple-color-palette.md",
"chars": 6511,
"preview": "---\ntitle: Simple Color Palette\nsubtitle: Create, view, and edit color palettes\npubDate: 2025-04-12\nplatforms:\n - macOS"
},
{
"path": "source/content/apps/spaced.md",
"chars": 1989,
"preview": "---\ntitle: Spaced\nsubtitle: Organize your menu bar items into groups\npubDate: 2023-01-20\nplatforms:\n - macOS\nisMenuBarA"
},
{
"path": "source/content/apps/speediness.md",
"chars": 6096,
"preview": "---\ntitle: Speediness\nsubtitle: Check your internet speed\npubDate: 2021-11-23\nplatforms:\n - macOS\nappStoreId: 159670646"
},
{
"path": "source/content/apps/supercharge.md",
"chars": 69675,
"preview": "---\ntitle: Supercharge\nsubtitle: Elevate your Mac experience\npubDate: 2024-09-29\nplatforms:\n - macOS\nisPaid: true\nisMen"
},
{
"path": "source/content/apps/system-color-picker.md",
"chars": 10167,
"preview": "---\ntitle: System Color Picker\nsubtitle: The familiar color picker supercharged\npubDate: 2021-05-01\nplatforms:\n - macOS"
},
{
"path": "source/content/apps/text-lens.md",
"chars": 5967,
"preview": "---\ntitle: Text Lens\nsubtitle: Copy unselectable text on screen\npubDate: 2025-03-29\nplatforms:\n - macOS\nisPaid: true\nis"
},
{
"path": "source/content/apps/today.md",
"chars": 6304,
"preview": "---\ntitle: Today\nsubtitle: Today’s schedule in your menu bar\npubDate: 2022-10-27\nplatforms:\n - macOS\nisMenuBarApp: true"
},
{
"path": "source/content/apps/touch-bar-simulator.md",
"chars": 496,
"preview": "---\ntitle: Touch Bar Simulator\nsubtitle: Use the Touch Bar on any Mac\npubDate: 2017-04-16\nisArchived: true\nplatforms:\n "
},
{
"path": "source/content/apps/utc-time.md",
"chars": 2467,
"preview": "---\ntitle: UTC Time\nsubtitle: Show the time in UTC in the menu bar or a widget\npubDate: 2021-03-16\nplatforms:\n - macOS\n"
},
{
"path": "source/content/apps/velja.md",
"chars": 48564,
"preview": "---\ntitle: Velja\nsubtitle: Powerful browser picker\npubDate: 2022-04-21\nplatforms:\n - macOS\nisPaid: true\nisMenuBarApp: t"
},
{
"path": "source/content/apps/week-number.md",
"chars": 2604,
"preview": "---\ntitle: Week Number\nsubtitle: The current week number in your menu bar\npubDate: 2024-05-19\nplatforms:\n - macOS\nisMen"
},
{
"path": "source/content/apps/zone-bar.md",
"chars": 3876,
"preview": "---\ntitle: Zone Bar\nsubtitle: World clocks in your menu bar\npubDate: 2025-11-20\nplatforms:\n - macOS\nisPaid: true\nisMenu"
},
{
"path": "source/content/blog/empathy-in-open-source.md",
"chars": 1381,
"preview": "---\ntitle: Empathy in Open Source\ndescription: Open source is not just about code, it's about people.\npubDate: 2023-05-2"
},
{
"path": "source/content/blog/goodbye-nodejs-buffer.md",
"chars": 7115,
"preview": "---\ntitle: Goodbye, Node.js Buffer\ndescription: It's time to move from Buffer to Uint8Array.\npubDate: 2023-10-24\ntags:\n "
},
{
"path": "source/content/blog/issue-bumping.md",
"chars": 1724,
"preview": "---\ntitle: Issue Bumping\npubDate: 2020-10-09\ntags:\n - open-source\n---\n\n\n\nI frequently recei"
},
{
"path": "source/content/blog/micro-benchmark-fallacy.md",
"chars": 2732,
"preview": "---\ntitle: The Micro-Benchmark Fallacy\ndescription: It's a trap.\npubDate: 2024-08-13\ntags:\n - programming\n---\n\nMicro-be"
},
{
"path": "source/content/blog/shortcutie-setapp.md",
"chars": 186,
"preview": "---\n#isUnlisted: true\ntitle: Shortcutie + Setapp = ❤️\ndescription: My Shortcutie app is now available on Setapp.\npubDate"
},
{
"path": "source/content/blog/small-focused-modules.md",
"chars": 4246,
"preview": "---\ntitle: Small Focused Modules\ndescription: Make small focused modules for reusability and to make it possible to buil"
},
{
"path": "source/content.config.ts",
"chars": 2526,
"preview": "import {defineCollection} from 'astro:content';\nimport {glob} from 'astro/loaders';\nimport {z} from 'astro/zod';\n\nconst "
},
{
"path": "source/data/apps-extra.json",
"chars": 2296,
"preview": "[\n\t{\n\t\t\"label\": \"Categories\",\n\t\t\"items\": [\n\t\t\t{\n\t\t\t\t\"title\": \"Free\",\n\t\t\t\t\"url\": \"/apps/free\",\n\t\t\t\t\"description\": \"Apps t"
},
{
"path": "source/env.d.ts",
"chars": 148,
"preview": "/* eslint-disable @typescript-eslint/triple-slash-reference */\n/// <reference path=\"../.astro/types.d.ts\" />\n/// <refere"
},
{
"path": "source/layouts/BaseLayout.astro",
"chars": 8776,
"preview": "---\nimport '../../styles/global.css';\nimport MetaTags from '~/components/core/MetaTags.astro';\n\nconst {meta = {}} = Astr"
},
{
"path": "source/layouts/BlogLayout.astro",
"chars": 402,
"preview": "---\nimport Layout from '~/layouts/PageLayout.astro';\n\nconst {meta} = Astro.props;\n---\n\n<Layout {meta}>\n\t<section class=\""
},
{
"path": "source/layouts/MarkdownLayout.astro",
"chars": 429,
"preview": "---\nimport Layout from '~/layouts/PageLayout.astro';\nimport {proseCSS} from '~/utils/apps.js';\n\nconst {frontmatter} = As"
},
{
"path": "source/layouts/PageLayout.astro",
"chars": 338,
"preview": "---\nimport Layout from '~/layouts/BaseLayout.astro';\nimport Header from '~/components/widgets/Header.astro';\nimport Foot"
},
{
"path": "source/layouts/SimplePageLayout.astro",
"chars": 506,
"preview": "---\nimport Layout from '~/layouts/PageLayout.astro';\nimport {proseCSS} from '~/utils/apps.js';\n\nconst {meta, title} = As"
},
{
"path": "source/pages/404.astro",
"chars": 1006,
"preview": "---\nimport {SITE} from '~/config.mjs';\nimport Layout from '~/layouts/PageLayout.astro';\n\nconst title = `Error 404 — ${SI"
},
{
"path": "source/pages/[...apps]/[slug]/privacy-policy.astro",
"chars": 1269,
"preview": "---\nimport Layout from '~/layouts/SimplePageLayout.astro';\nimport {fetchApps} from '~/utils/apps.js';\n\nexport async func"
},
{
"path": "source/pages/[...apps]/[slug]/release-notes.astro",
"chars": 1668,
"preview": "---\nimport {Icon} from 'astro-iconify';\nimport Layout from '~/layouts/SimplePageLayout.astro';\nimport {fetchFilteredRele"
},
{
"path": "source/pages/[...apps]/[slug]/rss.xml.js",
"chars": 991,
"preview": "import rss from '@astrojs/rss';\nimport sanitizeHtml from 'sanitize-html';\nimport {fetchFilteredReleases, releaseNotesMar"
},
{
"path": "source/pages/[...apps]/[slug].astro",
"chars": 21897,
"preview": "---\nimport {Icon} from 'astro-iconify';\nimport {SITE} from '~/config.mjs';\nimport Layout from '~/layouts/PageLayout.astr"
},
{
"path": "source/pages/[...blog]/[...page].astro",
"chars": 1141,
"preview": "---\nimport {SITE} from '~/config.mjs';\nimport Layout from '~/layouts/BlogLayout.astro';\nimport BlogList from '~/componen"
},
{
"path": "source/pages/[...blog]/[slug].astro",
"chars": 785,
"preview": "---\nimport {SITE} from '~/config.mjs';\nimport Layout from '~/layouts/PageLayout.astro';\nimport Post from '~/components/b"
},
{
"path": "source/pages/[...blog]/_[tag]/[...page].astro",
"chars": 1221,
"preview": "---\nimport {SITE, BLOG} from '~/config.mjs';\nimport Layout from '~/layouts/BlogLayout.astro';\nimport BlogList from '~/co"
},
{
"path": "source/pages/_apps-extra.astro",
"chars": 335,
"preview": "---\nimport appExtras from '../data/apps-extra.json';\n---\n\n{appExtras.map(group => (\n\t<>\n\t\t<h2>{group.label}</h2>\n\t\t<ul>\n"
},
{
"path": "source/pages/_apps-heatmap.astro",
"chars": 5168,
"preview": "---\nconst {apps} = Astro.props;\n\nconst WEEK_MS = 7 * 24 * 60 * 60 * 1000;\nconst currentYear = new Date().getFullYear();\n"
},
{
"path": "source/pages/about.md",
"chars": 2695,
"preview": "---\nlayout: ~/layouts/MarkdownLayout.astro\ntitle: About\n---\n\n# About Sindre Sorhus\n\nI'm a full-time open-source develope"
},
{
"path": "source/pages/apps/affiliates.md",
"chars": 273,
"preview": "---\nlayout: ~/layouts/MarkdownLayout.astro\ntitle: Affiliates\n---\n\n# Affiliates for my apps\n\nEarn money promoting some of"
},
{
"path": "source/pages/apps/archived.astro",
"chars": 226,
"preview": "---\nimport AppsCategory from '~/components/apps/AppsCategory.astro';\n---\n\n<AppsCategory\n\ttitle=\"Archived Apps\"\n\tdescript"
},
{
"path": "source/pages/apps/discounts.md",
"chars": 2746,
"preview": "---\nlayout: ~/layouts/MarkdownLayout.astro\ntitle: Discounts\n---\n\n# Discounts\n\n<!-- ## Black friday\n\nApps are on sale fro"
},
{
"path": "source/pages/apps/faq.md",
"chars": 23029,
"preview": "---\nlayout: ~/layouts/MarkdownLayout.astro\ntitle: Frequently Asked Questions\n---\n\n# Frequently Asked Questions\n\n*See the"
},
{
"path": "source/pages/apps/free.astro",
"chars": 552,
"preview": "---\nimport AppsCategory from '~/components/apps/AppsCategory.astro';\n---\n\n<AppsCategory\n\ttitle=\"Free Apps\"\n\tdescription="
},
{
"path": "source/pages/apps/ios.astro",
"chars": 228,
"preview": "---\nimport AppsCategory from '~/components/apps/AppsCategory.astro';\n---\n\n<AppsCategory\n\ttitle=\"iPhone & iPad Apps\"\n\tdes"
},
{
"path": "source/pages/apps/macos.astro",
"chars": 212,
"preview": "---\nimport AppsCategory from '~/components/apps/AppsCategory.astro';\n---\n\n<AppsCategory\n\ttitle=\"Mac Apps\"\n\tdescription=\""
},
{
"path": "source/pages/apps/menu-bar.astro",
"chars": 192,
"preview": "---\nimport AppsCategory from '~/components/apps/AppsCategory.astro';\n---\n\n<AppsCategory\n\ttitle=\"Menu Bar Apps\"\n\tdescript"
},
{
"path": "source/pages/apps/older-versions.astro",
"chars": 934,
"preview": "---\nimport {SITE} from '~/config.mjs';\nimport Layout from '~/layouts/SimplePageLayout.astro';\nimport {fetchApps} from '~"
},
{
"path": "source/pages/apps/paid.astro",
"chars": 356,
"preview": "---\nimport AppsCategory from '~/components/apps/AppsCategory.astro';\n---\n\n<AppsCategory\n\ttitle=\"Paid Apps\"\n\tdescription="
},
{
"path": "source/pages/apps/random.astro",
"chars": 860,
"preview": "---\nimport Layout from '~/layouts/SimplePageLayout.astro';\nimport {fetchApps} from '~/utils/apps.js';\n\nconst apps = awai"
},
{
"path": "source/pages/apps/setapp.astro",
"chars": 205,
"preview": "---\nimport AppsCategory from '~/components/apps/AppsCategory.astro';\n---\n\n<AppsCategory\n\ttitle=\"Setapp Apps\"\n\tdescriptio"
},
{
"path": "source/pages/apps/shortcuts.astro",
"chars": 324,
"preview": "---\nimport AppsCategory from '~/components/apps/AppsCategory.astro';\n---\n\n<AppsCategory\n\ttitle=\"Shortcuts Apps\"\n\tdescrip"
},
{
"path": "source/pages/apps/terms.md",
"chars": 2356,
"preview": "---\nlayout: ~/layouts/MarkdownLayout.astro\ntitle: Terms of Use\n---\n\n# Apps — Terms of Use\n\nPlease take a moment to famil"
},
{
"path": "source/pages/apps/visionos.astro",
"chars": 229,
"preview": "---\nimport AppsCategory from '~/components/apps/AppsCategory.astro';\n---\n\n<AppsCategory\n\ttitle=\"Apple Vision Apps\"\n\tdesc"
},
{
"path": "source/pages/apps/watchos.astro",
"chars": 226,
"preview": "---\nimport AppsCategory from '~/components/apps/AppsCategory.astro';\n---\n\n<AppsCategory\n\ttitle=\"Apple Watch Apps\"\n\tdescr"
},
{
"path": "source/pages/apps.astro",
"chars": 6222,
"preview": "---\nimport appExtras from '../data/apps-extra.json';\nimport AppsExtra from './_apps-extra.astro';\n/// import AppsHeatmap"
},
{
"path": "source/pages/contact.astro",
"chars": 11316,
"preview": "---\nimport PageLayout from '~/layouts/PageLayout.astro';\n\nconst meta = {\n\ttitle: 'Contact — Sindre Sorhus',\n};\n\nconst pa"
},
{
"path": "source/pages/donate.md",
"chars": 1350,
"preview": "---\nlayout: ~/layouts/MarkdownLayout.astro\ntitle: Donate\n---\n\n<style>\n.hero-body .column {\n\tmargin-bottom: 180px;\n}\n\n.he"
},
{
"path": "source/pages/feedback.astro",
"chars": 31592,
"preview": "---\nimport * as faqMd from './apps/faq.md';\nimport Layout from '~/layouts/PageLayout.astro';\nimport {fetchApps, proseCSS"
},
{
"path": "source/pages/feeds.astro",
"chars": 833,
"preview": "---\nimport MarkdownIt from 'markdown-it';\nimport MarkdownLayout from '~/layouts/MarkdownLayout.astro';\nimport {fetchApps"
},
{
"path": "source/pages/index.astro",
"chars": 25309,
"preview": "---\nimport {Icon} from 'astro-iconify';\nimport {SITE} from '~/config.mjs';\nimport Layout from '~/layouts/PageLayout.astr"
},
{
"path": "source/pages/og/[slug].png.js",
"chars": 3977,
"preview": "import process from 'node:process';\nimport fs from 'node:fs';\nimport {createHash} from 'node:crypto';\nimport path from '"
},
{
"path": "source/pages/repos.md",
"chars": 5270,
"preview": "---\nlayout: ~/layouts/MarkdownLayout.astro\ntitle: Repos\n---\n\n<style>\n\t#unicorn-icon {\n\t\tmargin-top: -30px;\n\t\tmargin-bott"
},
{
"path": "source/pages/rss-apps.xml.js",
"chars": 444,
"preview": "import rss from '@astrojs/rss';\nimport {fetchApps} from '~/utils/apps.js';\n\nexport const GET = async context => {\n\tlet i"
},
{
"path": "source/pages/rss-repos.xml.js",
"chars": 677,
"preview": "import rss from '@astrojs/rss';\nimport {githubApi} from '~/utils/utils.js';\n\nconst fetchRepos = async () => {\n\tconst rep"
},
{
"path": "source/pages/rss.xml.js",
"chars": 1089,
"preview": "import rss from '@astrojs/rss';\nimport {SITE} from '~/config.mjs';\nimport {fetchPosts} from '~/utils/posts.js';\nimport {"
},
{
"path": "source/pages/supporters.md",
"chars": 17604,
"preview": "---\nlayout: ~/layouts/MarkdownLayout.astro\ntitle: Supporters\n---\n\n<style is:inline>\n.reward-price {\n\tfont-size: 14px;\n\tp"
},
{
"path": "source/pages/tiny-apps.md",
"chars": 1045,
"preview": "---\nlayout: ~/layouts/MarkdownLayout.astro\ntitle: Tiny apps\n---\n\n# Tiny Apps\n\nTiny but useful macOS utilities. These are"
},
{
"path": "source/utils/apps.js",
"chars": 5419,
"preview": "import {markdown} from '@astropub/md';\nimport {getCollection, render} from 'astro:content';\n\nconst date30DaysAgo = new D"
},
{
"path": "source/utils/permalinks.js",
"chars": 1057,
"preview": "import {SITE} from '~/config.mjs';\n\nconst trim = (string_, ch) => {\n\tlet start = 0;\n\tlet end = string_.length;\n\n\twhile ("
},
{
"path": "source/utils/posts.js",
"chars": 902,
"preview": "import getReadingTime from 'reading-time';\nimport {getCollection, render} from 'astro:content';\n\nconst normalizePost = a"
},
{
"path": "source/utils/rehype-kbd-separator.js",
"chars": 1538,
"preview": "/**\nRehype plugin that splits `<kbd>Command+A</kbd>` into `<kbd>Command</kbd> + <kbd>A</kbd>`.\n\nAny `<kbd>` whose text c"
},
{
"path": "source/utils/remark-heading-meta.js",
"chars": 1915,
"preview": "/**\nRemark plugin that extracts `<!-- @namespace.attribute value -->` directives from HTML comments immediately followin"
},
{
"path": "source/utils/remark-inject-feedback-faq.js",
"chars": 1986,
"preview": "const feedbackId = 'feedback';\n\nconst getText = node =>\n\tnode.type === 'text' ? node.value : (node.children?.map(getText"
},
{
"path": "source/utils/remark-inject-feedback-faq.test.js",
"chars": 3275,
"preview": "import assert from 'node:assert/strict';\nimport {test} from 'node:test';\nimport {unified} from 'unified';\nimport remarkP"
},
{
"path": "source/utils/utils.js",
"chars": 2180,
"preview": "import MarkdownIt from 'markdown-it';\nimport {fetchApps} from '~/utils/apps.js';\n\nexport const releaseNotesMarkdownParse"
},
{
"path": "styles/global.css",
"chars": 7947,
"preview": "@import 'tailwindcss';\n@plugin '@tailwindcss/typography';\n@plugin '@tailwindcss/forms';\n\n@theme {\n\t--color-primary-50: #"
},
{
"path": "tsconfig.json",
"chars": 215,
"preview": "{\n\t\"extends\": \"astro/tsconfigs/base\",\n\t\"compilerOptions\": {\n\t\t\"types\": [\n\t\t\t\"astro/client\"\n\t\t],\n\t\t\"allowJs\": true,\n\t\t\"st"
}
]
// ... and 1 more files (download for full content)
About this extraction
This page contains the full source code of the sindresorhus/sindresorhus.github.com GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 159 files (742.6 KB), approximately 207.4k tokens, and a symbol index with 20 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.