efficient-shell 4.134.0 → 4.137.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +6 -17
- package/README.md +84 -8
- package/dist/Browser-ZX5OTOKK.js +43 -0
- package/dist/Calculator-4SQGOQFQ.js +29 -0
- package/dist/ConfirmDialog-NPKW2XHM.js +1 -0
- package/dist/CurrencyConverter-2KOM7L6V.js +21 -0
- package/dist/Documents-IZTIQYPG.js +52 -0
- package/dist/Files-B63KKXGZ.js +89 -0
- package/dist/Notepad-WA77V45J.js +25 -0
- package/dist/PdfViewer-RBRGEKWF.js +1 -0
- package/dist/PomodoroTimer-SDUBKXUS.js +99 -0
- package/dist/Preview-D4KOA4OI.js +187 -0
- package/dist/Sidebar-Y57LYXXI.js +23 -0
- package/dist/Spreadsheet-JX5E6WH6.js +37 -0
- package/dist/Stock-XAQ5WMUZ.js +16 -0
- package/dist/Weather-HLAGJ5LV.js +60 -0
- package/dist/WorldClock-IRI4VCTA.js +32 -0
- package/dist/apps/index.js +1 -151
- package/dist/brand.css +1 -1
- package/dist/chunk-3A46NCXK.js +29 -0
- package/dist/chunk-44UO7FYU.js +11 -0
- package/dist/chunk-466CM2TJ.js +1 -0
- package/dist/chunk-57MIENLJ.js +1 -0
- package/dist/chunk-5CRAF2AD.js +2 -0
- package/dist/chunk-A2OQLLYK.js +6 -0
- package/dist/chunk-B43AGQET.js +4 -0
- package/dist/chunk-BR22X7E5.js +1 -0
- package/dist/chunk-BUTSU7FO.js +1 -0
- package/dist/chunk-D65T4H6J.js +1 -0
- package/dist/chunk-ESL5TDNA.js +1 -0
- package/dist/chunk-FBDZGO3V.js +1 -0
- package/dist/chunk-FHTLC7HH.js +1 -0
- package/dist/chunk-FQLMX3IE.js +948 -0
- package/dist/chunk-H562R4GX.js +34 -0
- package/dist/chunk-JN4WXTWJ.js +106 -0
- package/dist/chunk-LVDRBRYU.js +1 -0
- package/dist/chunk-LWLCNQY7.js +1 -0
- package/dist/chunk-MAIHBBWT.js +1 -0
- package/dist/chunk-NPJH5MD7.js +13 -0
- package/dist/chunk-OCSOMMY2.js +1 -0
- package/dist/chunk-OQDWLHZI.js +1 -0
- package/dist/chunk-OWSAMA3I.js +23 -0
- package/dist/chunk-PH3PRIFP.js +5 -0
- package/dist/chunk-TAWKWSPN.js +9 -0
- package/dist/chunk-U4GTZPXP.js +1 -0
- package/dist/chunk-UB4JIOLD.js +2 -0
- package/dist/chunk-UZAJ5BF6.js +9 -0
- package/dist/chunk-VEGMDXT4.js +1 -0
- package/dist/chunk-VTVSMRFX.js +1 -0
- package/dist/chunk-VVAGSKW7.js +1 -0
- package/dist/chunk-XO43FJRM.js +19 -0
- package/dist/chunk-Y7BOLDRM.js +69 -0
- package/dist/file-intake/index.js +1 -4
- package/dist/{index-DZ7E7bCl.d.ts → index-DVI9DMSu.d.ts} +189 -18
- package/dist/index.d.ts +2 -2
- package/dist/index.js +639 -7473
- package/dist/map/index.js +20 -540
- package/dist/markdown/index.js +6 -184
- package/dist/markup/index.js +1 -135
- package/dist/page-tabs/index.js +21 -709
- package/dist/sounds-OMHXVVQ4.js +1 -0
- package/dist/ui/index.d.ts +1 -1
- package/dist/ui/index.js +1 -19
- package/dist/ui.css +78 -10
- package/package.json +4 -3
- package/dist/Browser-O3QZGUF2.js +0 -482
- package/dist/Browser-O3QZGUF2.js.map +0 -1
- package/dist/Calculator-L6N5X3KU.js +0 -192
- package/dist/Calculator-L6N5X3KU.js.map +0 -1
- package/dist/ConfirmDialog-LYSSZSUD.js +0 -4
- package/dist/ConfirmDialog-LYSSZSUD.js.map +0 -1
- package/dist/CurrencyConverter-64MKXB3D.js +0 -236
- package/dist/CurrencyConverter-64MKXB3D.js.map +0 -1
- package/dist/Documents-5WXXYCLI.js +0 -441
- package/dist/Documents-5WXXYCLI.js.map +0 -1
- package/dist/Files-AUURUUDN.js +0 -805
- package/dist/Files-AUURUUDN.js.map +0 -1
- package/dist/Notepad-GPXJVPB7.js +0 -410
- package/dist/Notepad-GPXJVPB7.js.map +0 -1
- package/dist/PdfViewer-HKO6P4SR.js +0 -5
- package/dist/PdfViewer-HKO6P4SR.js.map +0 -1
- package/dist/PomodoroTimer-4TQBWLP2.js +0 -633
- package/dist/PomodoroTimer-4TQBWLP2.js.map +0 -1
- package/dist/Preview-FOZYPKM2.js +0 -2959
- package/dist/Preview-FOZYPKM2.js.map +0 -1
- package/dist/Sidebar-BPU7RCZP.js +0 -291
- package/dist/Sidebar-BPU7RCZP.js.map +0 -1
- package/dist/Spreadsheet-3C66BBBF.js +0 -519
- package/dist/Spreadsheet-3C66BBBF.js.map +0 -1
- package/dist/Stock-IF4IHYLU.js +0 -158
- package/dist/Stock-IF4IHYLU.js.map +0 -1
- package/dist/Weather-725PFR7T.js +0 -431
- package/dist/Weather-725PFR7T.js.map +0 -1
- package/dist/WorldClock-UU4NZIQ7.js +0 -202
- package/dist/WorldClock-UU4NZIQ7.js.map +0 -1
- package/dist/apps/index.js.map +0 -1
- package/dist/chunk-2TPTHAKI.js +0 -316
- package/dist/chunk-2TPTHAKI.js.map +0 -1
- package/dist/chunk-4P44JXDS.js +0 -195
- package/dist/chunk-4P44JXDS.js.map +0 -1
- package/dist/chunk-5O42JXQE.js +0 -26
- package/dist/chunk-5O42JXQE.js.map +0 -1
- package/dist/chunk-72CQWN7O.js +0 -547
- package/dist/chunk-72CQWN7O.js.map +0 -1
- package/dist/chunk-7CCHEEYC.js +0 -94
- package/dist/chunk-7CCHEEYC.js.map +0 -1
- package/dist/chunk-BE7FZOFU.js +0 -17
- package/dist/chunk-BE7FZOFU.js.map +0 -1
- package/dist/chunk-D276EMXS.js +0 -57
- package/dist/chunk-D276EMXS.js.map +0 -1
- package/dist/chunk-D7PYW2QS.js +0 -265
- package/dist/chunk-D7PYW2QS.js.map +0 -1
- package/dist/chunk-DVZWYWSD.js +0 -26
- package/dist/chunk-DVZWYWSD.js.map +0 -1
- package/dist/chunk-ET6ID4LP.js +0 -102
- package/dist/chunk-ET6ID4LP.js.map +0 -1
- package/dist/chunk-GA35NEND.js +0 -56
- package/dist/chunk-GA35NEND.js.map +0 -1
- package/dist/chunk-GIGV2ZRW.js +0 -70
- package/dist/chunk-GIGV2ZRW.js.map +0 -1
- package/dist/chunk-IPXN646P.js +0 -14
- package/dist/chunk-IPXN646P.js.map +0 -1
- package/dist/chunk-IRWSRJ4K.js +0 -48
- package/dist/chunk-IRWSRJ4K.js.map +0 -1
- package/dist/chunk-IULP5BCD.js +0 -79
- package/dist/chunk-IULP5BCD.js.map +0 -1
- package/dist/chunk-MGGY74RY.js +0 -14
- package/dist/chunk-MGGY74RY.js.map +0 -1
- package/dist/chunk-OLJDJYSU.js +0 -13678
- package/dist/chunk-OLJDJYSU.js.map +0 -1
- package/dist/chunk-PIGDNN5F.js +0 -46
- package/dist/chunk-PIGDNN5F.js.map +0 -1
- package/dist/chunk-Q2MJVSJT.js +0 -7
- package/dist/chunk-Q2MJVSJT.js.map +0 -1
- package/dist/chunk-Q3LT745N.js +0 -3710
- package/dist/chunk-Q3LT745N.js.map +0 -1
- package/dist/chunk-QAGQRNKI.js +0 -145
- package/dist/chunk-QAGQRNKI.js.map +0 -1
- package/dist/chunk-QRL64J5F.js +0 -503
- package/dist/chunk-QRL64J5F.js.map +0 -1
- package/dist/chunk-QSKCQUZE.js +0 -1103
- package/dist/chunk-QSKCQUZE.js.map +0 -1
- package/dist/chunk-R4OQIQYX.js +0 -153
- package/dist/chunk-R4OQIQYX.js.map +0 -1
- package/dist/chunk-RT6DSB5Y.js +0 -143
- package/dist/chunk-RT6DSB5Y.js.map +0 -1
- package/dist/chunk-SHQM5CK3.js +0 -549
- package/dist/chunk-SHQM5CK3.js.map +0 -1
- package/dist/chunk-T4VQHMG4.js +0 -822
- package/dist/chunk-T4VQHMG4.js.map +0 -1
- package/dist/chunk-TRCWINHF.js +0 -105
- package/dist/chunk-TRCWINHF.js.map +0 -1
- package/dist/chunk-TW7LPMVR.js +0 -16
- package/dist/chunk-TW7LPMVR.js.map +0 -1
- package/dist/chunk-W622KQTD.js +0 -465
- package/dist/chunk-W622KQTD.js.map +0 -1
- package/dist/chunk-X4Q6G253.js +0 -416
- package/dist/chunk-X4Q6G253.js.map +0 -1
- package/dist/chunk-YNKK7NE3.js +0 -171
- package/dist/chunk-YNKK7NE3.js.map +0 -1
- package/dist/chunk-YPO6RDMX.js +0 -20
- package/dist/chunk-YPO6RDMX.js.map +0 -1
- package/dist/file-intake/index.js.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/map/index.js.map +0 -1
- package/dist/markdown/index.js.map +0 -1
- package/dist/markup/index.js.map +0 -1
- package/dist/page-tabs/index.js.map +0 -1
- package/dist/sounds-NT4DEZGD.js +0 -3
- package/dist/sounds-NT4DEZGD.js.map +0 -1
- package/dist/ui/index.js.map +0 -1
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/forms/buttonStyles.ts","../src/forms/Button.tsx"],"names":["Button"],"mappings":"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","file":"chunk-RT6DSB5Y.js","sourcesContent":["/**\n * Button styling — the class strings `Button` and `IconButton` wear, and the\n * two public functions that compose them, `buttonClasses` and\n * `iconButtonClasses`. Both components call those functions, so the look a host\n * borrows and the look the kit renders are one string, not two that agree.\n *\n * A module of its own, beside forms/styles.ts and for the reason that one\n * exists: the look is a value a host needs WITHOUT the component. A link drawn\n * as a button — \"Add a business\", \"View invoice\" — has to be an `<a>`, so it\n * can be middle-clicked, opened in a new tab and read off the status bar, and\n * `Button` can only render a `<button>`. Until these were exported, a host's\n * only way to that look was to copy the strings, and a copy is wrong from the\n * first release that touches the original.\n *\n * Named after `inputClasses`, which is the same idea for a text field. Not IN\n * forms/styles.ts: that module is the input look, its strings are pinned as\n * contract by `tests/touchPrimitives.test.tsx`, and the button's types and\n * ladders would double it to say something else. And React-free, like that\n * one: nothing here renders, so nothing here imports React. That keeps the door\n * open to re-exporting both from an entry without `\"use client\"` — the only way\n * a server component could ever CALL them. Through `efficient-shell/ui` they are\n * client references like every kit function (README → \"Server rendering\").\n */\n\n/**\n * `ghost-danger` is a destructive action sitting in a row of ordinary ones —\n * Clear, Discard, Remove — where solid `danger` would be wrong. Two solid\n * shouting buttons on one screen means neither is read, so the destructive one\n * borrows `ghost`'s weight and keeps only the colour. The colour is the point:\n * it lets someone tell what the button costs WITHOUT reading it, which under\n * time pressure is what actually happens.\n */\nexport type ButtonVariant = 'primary' | 'secondary' | 'ghost' | 'ghost-danger' | 'danger' | 'link';\n/**\n * `sm`/`md`/`lg` are the desktop scale. The `touch-*` rungs are for a finger on\n * glass — a till, a warehouse tablet — and are a SEPARATE ladder on purpose:\n * a till's idea of \"medium\" is 56px, and naming it `md` would have made the\n * same word mean two sizes depending on which app you were reading.\n *\n * Nothing picks a touch size automatically. An app that wants them asks for\n * them, so a desktop portal cannot grow finger-sized buttons by accident.\n */\nexport type ButtonSize = 'sm' | 'md' | 'lg' | 'touch-sm' | 'touch' | 'touch-lg' | 'touch-xl';\n\n/**\n * Shared with `IconButton`'s composition below, which builds its own class\n * string rather than passing a square size through `buttonClasses`' `className`\n * — two competing padding utilities in one attribute resolve by\n * compiled-stylesheet order, not by the order they were written (the reasoning\n * in forms/styles.ts applies here identically).\n *\n * The PARTS stay module-private, and that is deliberate: the public way to the\n * look is the composed string. Composing is where the rules live — the `link`\n * variant does not override the box, it never receives it — and a host\n * assembling `BUTTON_BASE + BUTTON_VARIANTS.link + …` by hand would put the\n * box back. A host restyling the parts would also be a host the theme system\n * cannot reach; one wearing the whole string is reached like the kit is.\n */\nconst BUTTON_BASE =\n 'inline-flex items-center justify-center rounded-md font-medium transition-colors ' +\n 'rosh-focus-ring focus-visible:ring-2 disabled:cursor-not-allowed disabled:opacity-60';\n\nconst BUTTON_VARIANTS: Record<ButtonVariant, string> = {\n primary: 'bg-blue-600 text-white shadow-sm hover:bg-blue-700 focus-visible:ring-[color:var(--rosh-focus-ring-strong)]',\n secondary: 'border border-gray-300 bg-white text-gray-700 shadow-sm hover:bg-gray-50 focus-visible:ring-[color:var(--rosh-focus-ring)]',\n ghost: 'text-gray-700 hover:bg-gray-100 focus-visible:ring-[color:var(--rosh-focus-ring)]',\n 'ghost-danger': 'text-red-600 hover:bg-red-50 focus-visible:ring-[color:var(--rosh-focus-ring-invalid)]',\n danger: 'bg-red-600 text-white shadow-sm hover:bg-red-700 focus-visible:ring-[color:var(--rosh-focus-ring-invalid-strong)]',\n /**\n * A button that reads as a link: no box, no padding, underlined on hover.\n * For an action that belongs in running text or beside a field — \"Forgot\n * your password?\", \"Use a different address\" — where a boxed button would\n * claim more of the page than the action deserves.\n *\n * `Button` with this variant is still a <button>. Anything that NAVIGATES\n * should be an anchor, so it can be middle-clicked and read off the status\n * bar; this is for actions that merely look quiet. An anchor that wants this\n * look takes it from `buttonClasses({ variant: 'link' })`.\n */\n link: 'text-blue-600 underline-offset-4 hover:underline focus-visible:ring-[color:var(--rosh-focus-ring)]',\n};\n\n// A Record keyed by the union, not a ternary chain: adding a member without a\n// size here is then a compile error rather than a silent fall-through to the\n// default branch. `sm`/`md` are byte-for-byte what they have always been, and\n// `tests/touchPrimitives.test.tsx` pins them against a captured literal.\n//\n// Every rung is also asserted to be the same height as the IconButton rung of\n// the same name (`tests/buttonLinkAndLarge.test.tsx`) — pinning the two sides\n// separately is how `lg` first shipped 4px short of its square twin.\n//\n// The touch rungs carry an explicit `h-*` where the desktop pair uses `py-*`.\n// That is deliberate: a hit target has to be a guaranteed height, not a height\n// implied by the current font size. They are separate map entries and never\n// concatenated with each other, so no two competing utilities land in one class\n// attribute.\nconst SIZES: Record<ButtonSize, string> = {\n sm: 'gap-1 px-2.5 py-1 text-xs',\n md: 'gap-1.5 px-3 py-1.5 text-sm',\n // `py-2.5`, not `py-2`: this rung has to come out 40px to match IconButton's\n // `h-10`, which is the promise IconButton's docblock makes for every rung.\n // `py-2` gives 36px (20px line box + 8px twice) and puts a 4px step between a\n // Button and an IconButton sitting in the same row.\n lg: 'gap-2 px-4 py-2.5 text-sm',\n // 44px is the WCAG 2.5.5 floor, and a floor is not a comfortable size. Use it\n // ONLY for chrome that sits outside the task — switching screens, ending a\n // shift — and never on the path someone is actually working through. It\n // exists so a dense toolbar has something legitimate to reach for instead of\n // borrowing the desktop `sm`, which is half this height.\n 'touch-sm': 'gap-1.5 h-11 px-4 text-base',\n 'touch': 'gap-2 h-14 px-5 text-base', // 56px — the comfortable default\n 'touch-lg': 'gap-2 h-16 px-6 text-lg', // 64px — primary action on a page\n 'touch-xl': 'gap-3 h-20 px-8 text-2xl', // 80px — keypad keys, tender\n};\n\n// Everything BUTTON_BASE has except the box: no rounding (there is nothing to\n// round) and no `justify-center` (a link sits in a line of text, it does not\n// centre itself in a shape).\nconst LINK_BASE =\n 'inline-flex items-center font-medium transition-colors ' +\n 'rosh-focus-ring focus-visible:ring-2 disabled:cursor-not-allowed disabled:opacity-60';\n\n// Only the gap and the text size survive from each rung — the padding is what\n// the link variant exists to shed.\nconst LINK_SIZES: Record<ButtonSize, string> = {\n sm: 'gap-1 text-xs',\n md: 'gap-1.5 text-sm',\n lg: 'gap-2 text-sm',\n 'touch-sm': 'gap-1.5 text-base',\n 'touch': 'gap-2 text-base',\n 'touch-lg': 'gap-2 text-lg',\n 'touch-xl': 'gap-3 text-2xl',\n};\n\n/**\n * Square, and matching `Button`'s heights rung for rung: `sm` is 24px in both\n * (py-1 either side of a 16px line box), `md` 32px, and the touch rungs carry\n * the same explicit heights for the same reason — a hit target has to be a\n * guaranteed size, not one implied by the current font.\n *\n * A Record keyed by the union, so a new ButtonSize member without an entry here\n * is a compile error rather than a silent fall-through.\n */\nconst SQUARE: Record<ButtonSize, string> = {\n sm: 'h-6 w-6',\n md: 'h-8 w-8',\n lg: 'h-10 w-10',\n 'touch-sm': 'h-11 w-11',\n 'touch': 'h-14 w-14',\n 'touch-lg': 'h-16 w-16',\n 'touch-xl': 'h-20 w-20',\n};\n\n/** What `buttonClasses` takes: `Button`'s look props, and nothing that behaves. */\nexport interface ButtonClassesOptions {\n /** Defaults to `primary`, as `Button`'s does. */\n variant?: ButtonVariant;\n /** Defaults to `md`, as `Button`'s does. */\n size?: ButtonSize;\n /** Stretch to the full width of the container (`w-full`). */\n block?: boolean;\n /**\n * Appended last, exactly as `Button` appends its `className`. For layout —\n * a margin, `shrink-0` — never a second padding, colour or display: those\n * compete with the string's own and resolve by compiled-stylesheet order.\n */\n className?: string;\n}\n\n/**\n * The class string `Button` puts on its `<button>` for the same inputs, with\n * the same defaults. `Button` renders through this function, so the two cannot\n * disagree; `tests/buttonClasses.test.tsx` holds them equal for every variant\n * and size.\n *\n * It is for an element that has to look like a button and cannot be one —\n * above all a link, a router's link included:\n *\n * <Link href=\"/organisations/new\" className={buttonClasses({ variant: 'secondary' })}>\n * Add a business\n * </Link>\n *\n * A `<button>` gets some of its behaviour from being a button, and the string\n * cannot hand that to an `<a>`. What the anchor needs instead:\n *\n * - **Disabled is not an attribute of `<a>`.** The string's `disabled:`\n * variants match `:disabled`, which an anchor never is: on an `<a>` they are\n * inert — harmless, and no help. A link that cannot be followed should stop\n * being one: drop the `href`, which leaves it neither focusable nor\n * followable — and without a role, so give it `role=\"link\"` back with\n * `aria-disabled=\"true\"`, and it is announced as a link that is unavailable\n * rather than as plain text. Dim it with `opacity-60 cursor-not-allowed` in\n * `className`, which compete with nothing here. A Next `<Link>` requires an `href`, so a\n * disabled one is a bare `<a>` — or, simpler and better, a disabled `Button`,\n * which does all of that and also takes `disabledReason`.\n * - **The cursor differs.** The string sets none (only the inert\n * `disabled:cursor-not-allowed`). An `<a href>` shows the pointer from the\n * browser's own stylesheet; a `<button>` shows whatever the host's preflight\n * gives it, which under Tailwind v4 is the plain arrow. So a row with one of\n * each shows two cursors. Settle it once, for both, in the host's base layer\n * — `button:not(:disabled) { cursor: pointer }` is the line in Tailwind's\n * own v4 upgrade guide — rather than per call, where it would drift.\n * - **Display is `inline-flex`, and must stay so.** An `<a>` is inline, and an\n * inline box ignores `height` and takes no room for vertical padding: the\n * string's `inline-flex` is what gives it the button's box, its touch-rung\n * height and the gap between an icon and its label. Never pass another\n * display utility (`flex`, `block`) in `className` — two in one attribute\n * resolve by stylesheet order. For full width ask for `block: true`, which\n * keeps `inline-flex` and adds `w-full`.\n * - **Without preflight, an `<a>` keeps its underline.** Tailwind's\n * preflight makes an anchor inherit its text decoration; a host running the\n * kit without it gets the browser's underline under every label, so add\n * `no-underline` there.\n *\n * `loading`, `leftIcon`/`rightIcon` and `disabledReason` are `Button`'s alone.\n * Put an icon in as a child — the size's `gap-*` spaces it as the slots do.\n *\n * Through `efficient-shell/ui` this is a client reference, like every kit\n * function: call it in a `'use client'` module. A server component that\n * imports it receives a reference it cannot call.\n */\nexport function buttonClasses({\n variant = 'primary',\n size = 'md',\n block = false,\n className = '',\n}: ButtonClassesOptions = {}): string {\n const link = variant === 'link';\n return [\n // `link` takes the base WITHOUT the box: no rounding, no padding from the\n // size table. It cannot cancel those by overriding — two padding utilities\n // in one class attribute resolve by compiled-stylesheet order, not by the\n // order they were written — so it never receives them, and keeps only the\n // size's gap and text size.\n link ? LINK_BASE : BUTTON_BASE,\n BUTTON_VARIANTS[variant],\n link ? LINK_SIZES[size] : SIZES[size],\n block ? 'w-full' : '',\n className,\n ].filter(Boolean).join(' ');\n}\n\n/** What `iconButtonClasses` takes: `IconButton`'s look props. */\nexport interface IconButtonClassesOptions {\n /**\n * Defaults to `ghost`, as `IconButton`'s does. `link` is excluded for the\n * reason it is excluded there: it exists to shed the box, and a square icon\n * button is nothing but the box.\n */\n variant?: Exclude<ButtonVariant, 'link'>;\n /** Defaults to `md`. Square, and the same height as `buttonClasses`' rung. */\n size?: ButtonSize;\n /** Appended last; the same rule as `ButtonClassesOptions.className`. */\n className?: string;\n}\n\n/**\n * The class string `IconButton` puts on its `<button>`, for an icon-only link\n * — a row's \"open\" arrow, an \"open in a new tab\" glyph. `IconButton` renders\n * through it, as `Button` does through `buttonClasses`.\n *\n * Everything `buttonClasses` says about an `<a>` holds here, and one thing\n * more, which is the reason `IconButton` is a component of its own: it REQUIRES\n * an `aria-label` in its props, so forgetting the name is a compile error. A\n * class string cannot require anything. An icon-only `<a>` without an\n * `aria-label` is a link with no name, read out as its URL or not at all — put\n * one on it.\n */\nexport function iconButtonClasses({\n variant = 'ghost',\n size = 'md',\n className = '',\n}: IconButtonClassesOptions = {}): string {\n return [BUTTON_BASE, BUTTON_VARIANTS[variant], SQUARE[size], 'shrink-0 p-0', className]\n .filter(Boolean)\n .join(' ');\n}\n","/**\n * Button — the kit's standard button. `primary` uses `bg-blue-600`, which the\n * theme system remaps to the active accent (and to a readable tone in dark\n * mode), so a primary button always follows the user's chosen accent.\n *\n * Controlled by the consumer like any native button (spread `onClick`, `type`,\n * `form`, …); the component only adds the look, a `loading` spinner state, and\n * optional icon slots.\n */\nimport { forwardRef, useId, type ButtonHTMLAttributes, type ReactNode } from 'react';\n\n// The look lives in ./buttonStyles, React-free, so a host can wear it on an\n// element that is not a <button> (`buttonClasses`). The types travel with it\n// and are re-exported here, where every import of them has always pointed.\nimport { buttonClasses, type ButtonSize, type ButtonVariant } from './buttonStyles';\n\nexport type { ButtonSize, ButtonVariant } from './buttonStyles';\n\nexport interface ButtonProps extends Omit<ButtonHTMLAttributes<HTMLButtonElement>, 'className'> {\n variant?: ButtonVariant;\n size?: ButtonSize;\n /** Show a spinner and disable the button while an action is in flight. */\n loading?: boolean;\n leftIcon?: ReactNode;\n rightIcon?: ReactNode;\n /** Stretch to the full width of the container. */\n block?: boolean;\n className?: string;\n /**\n * Why this button is disabled, rendered as text BESIDE it — never as a\n * `title` tooltip. A tooltip needs a hover, a touchscreen has no hover, and a\n * cashier facing a dead button with no explanation calls a manager.\n *\n * Only rendered while the button is actually disabled (or loading); ignored\n * otherwise, so it is safe to pass unconditionally. Note it changes the\n * rendered shape: the button gains a wrapper element, which matters to a\n * parent `flex gap-*` row or a `:first-child` selector.\n */\n disabledReason?: ReactNode;\n}\n\nfunction Spinner() {\n return (\n <svg className=\"h-3.5 w-3.5 animate-spin\" viewBox=\"0 0 24 24\" fill=\"none\" aria-hidden=\"true\">\n <circle className=\"opacity-25\" cx=\"12\" cy=\"12\" r=\"10\" stroke=\"currentColor\" strokeWidth=\"4\" />\n <path className=\"opacity-75\" fill=\"currentColor\" d=\"M4 12a8 8 0 018-8v4a4 4 0 00-4 4H4z\" />\n </svg>\n );\n}\n\nconst Button = forwardRef<HTMLButtonElement, ButtonProps>(function Button(\n { variant = 'primary', size = 'md', loading = false, leftIcon, rightIcon, block = false,\n disabled, type = 'button', children, className = '', disabledReason, ...rest },\n ref,\n) {\n // useId, not a module counter: a counter assigns different ids on the server\n // and the client and breaks hydration. Called unconditionally — it is a hook.\n const generatedId = useId();\n const isDisabled = disabled || loading;\n const showReason = isDisabled && disabledReason != null && disabledReason !== '';\n const reasonId = showReason ? generatedId : undefined;\n\n const button = (\n <button\n ref={ref}\n type={type}\n disabled={isDisabled}\n aria-busy={loading || undefined}\n aria-describedby={reasonId}\n // The one place this component's look is decided — and the same call a\n // host makes to put that look on a link. `loading`, `disabled` and\n // `disabledReason` change the element and its wrapper, never the string.\n className={buttonClasses({ variant, size, block, className })}\n {...rest}\n >\n {loading ? <Spinner /> : leftIcon}\n {children}\n {!loading && rightIcon}\n </button>\n );\n\n // No reason to show ⇒ the bare <button>, byte-identical to every release\n // before this prop existed. Only the disabled-with-a-reason case wraps.\n if (!showReason) return button;\n\n return (\n <span className={block ? 'flex w-full flex-col gap-1' : 'inline-flex flex-col items-start gap-1'}>\n {button}\n <span id={reasonId} className=\"text-xs text-red-600\">{disabledReason}</span>\n </span>\n );\n});\n\nexport default Button;\n"]}
|
package/dist/chunk-SHQM5CK3.js
DELETED
|
@@ -1,549 +0,0 @@
|
|
|
1
|
-
import { toast_default } from './chunk-4P44JXDS.js';
|
|
2
|
-
import { useShellPrefs } from './chunk-2TPTHAKI.js';
|
|
3
|
-
import { useSyncExternalStore, useCallback, useMemo } from 'react';
|
|
4
|
-
|
|
5
|
-
// src/shell/pomodoroStore.ts
|
|
6
|
-
var ALARM_OPTIONS = [
|
|
7
|
-
{ id: "bell", label: "Bell", description: "Soft bell with one harmonic" },
|
|
8
|
-
{ id: "chime", label: "Chime", description: "Two-note ascending chime" },
|
|
9
|
-
{ id: "bowl", label: "Singing Bowl", description: "Long-decay meditation tone" },
|
|
10
|
-
{ id: "wind-chimes", label: "Wind Chimes", description: "Four soft tones in succession" },
|
|
11
|
-
{ id: "off", label: "Off (silent)", description: "No sound \u2014 only desktop notification" }
|
|
12
|
-
];
|
|
13
|
-
var FOCUS_SOUND_OPTIONS = [
|
|
14
|
-
{ id: "none", label: "None" },
|
|
15
|
-
{ id: "tick-fast", label: "Ticking Fast" },
|
|
16
|
-
{ id: "tick-slow", label: "Ticking Slow" },
|
|
17
|
-
{ id: "rain", label: "Rain" },
|
|
18
|
-
{ id: "fireplace", label: "Fireplace" },
|
|
19
|
-
{ id: "white", label: "White Noise" },
|
|
20
|
-
{ id: "pink", label: "Pink Noise" },
|
|
21
|
-
{ id: "brown", label: "Brown Noise" }
|
|
22
|
-
];
|
|
23
|
-
var todayKey = () => `pomodoro-${(/* @__PURE__ */ new Date()).toISOString().slice(0, 10)}`;
|
|
24
|
-
var loadCount = () => {
|
|
25
|
-
try {
|
|
26
|
-
return parseInt(localStorage.getItem(todayKey()) || "0", 10) || 0;
|
|
27
|
-
} catch {
|
|
28
|
-
return 0;
|
|
29
|
-
}
|
|
30
|
-
};
|
|
31
|
-
var saveCount = (n) => {
|
|
32
|
-
try {
|
|
33
|
-
localStorage.setItem(todayKey(), String(n));
|
|
34
|
-
} catch {
|
|
35
|
-
}
|
|
36
|
-
};
|
|
37
|
-
var _durations = { focus: 25 * 60, short: 5 * 60, long: 15 * 60 };
|
|
38
|
-
var _alarm = "bell";
|
|
39
|
-
var _alarmVolume = 100;
|
|
40
|
-
var _alarmRepeat = 1;
|
|
41
|
-
var _focusSoundType = "none";
|
|
42
|
-
var _focusVolume = 50;
|
|
43
|
-
var _behaviour = { autoStartBreaks: false, autoStartPomodoros: false, longBreakInterval: 4 };
|
|
44
|
-
var _state = {
|
|
45
|
-
running: false,
|
|
46
|
-
remaining: _durations.focus,
|
|
47
|
-
mode: "focus",
|
|
48
|
-
total: _durations.focus,
|
|
49
|
-
streak: 0,
|
|
50
|
-
count: typeof localStorage !== "undefined" ? loadCount() : 0
|
|
51
|
-
};
|
|
52
|
-
var _intervalId = null;
|
|
53
|
-
var _listeners = /* @__PURE__ */ new Set();
|
|
54
|
-
var _notify = () => _listeners.forEach((l) => l());
|
|
55
|
-
var _set = (s) => {
|
|
56
|
-
_state = { ..._state, ...s };
|
|
57
|
-
_notify();
|
|
58
|
-
};
|
|
59
|
-
function getPomoSnapshot() {
|
|
60
|
-
return _state;
|
|
61
|
-
}
|
|
62
|
-
function subscribePomo(l) {
|
|
63
|
-
_listeners.add(l);
|
|
64
|
-
return () => {
|
|
65
|
-
_listeners.delete(l);
|
|
66
|
-
};
|
|
67
|
-
}
|
|
68
|
-
function setPomoDurations(d) {
|
|
69
|
-
_durations = d;
|
|
70
|
-
if (!_state.running && _state.remaining === _state.total) {
|
|
71
|
-
_set({ remaining: d[_state.mode], total: d[_state.mode] });
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
function setPomoAlarm(a) {
|
|
75
|
-
_alarm = a;
|
|
76
|
-
}
|
|
77
|
-
function setPomoAlarmConfig(volume, repeat) {
|
|
78
|
-
_alarmVolume = Math.max(0, Math.min(100, Math.round(volume)));
|
|
79
|
-
_alarmRepeat = Math.max(1, Math.min(5, Math.round(repeat)));
|
|
80
|
-
}
|
|
81
|
-
function setPomoBehaviour(b) {
|
|
82
|
-
_behaviour = {
|
|
83
|
-
autoStartBreaks: !!b.autoStartBreaks,
|
|
84
|
-
autoStartPomodoros: !!b.autoStartPomodoros,
|
|
85
|
-
longBreakInterval: Math.max(1, Math.min(20, Math.round(b.longBreakInterval || 4)))
|
|
86
|
-
};
|
|
87
|
-
}
|
|
88
|
-
function setPomoFocusSound(type, volume) {
|
|
89
|
-
_focusSoundType = type;
|
|
90
|
-
_focusVolume = Math.max(0, Math.min(100, Math.round(volume)));
|
|
91
|
-
if (_state.running && _state.mode === "focus") {
|
|
92
|
-
stopFocusAudio();
|
|
93
|
-
startFocusAudio();
|
|
94
|
-
} else if (type === "none" || _focusVolume === 0) {
|
|
95
|
-
stopFocusAudio();
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
function pomoStart() {
|
|
99
|
-
if (_state.running) return;
|
|
100
|
-
_set({ running: true });
|
|
101
|
-
_intervalId = setInterval(_tick, 1e3);
|
|
102
|
-
if (_state.mode === "focus") startFocusAudio();
|
|
103
|
-
}
|
|
104
|
-
function pomoPause() {
|
|
105
|
-
if (!_state.running && _intervalId === null) return;
|
|
106
|
-
if (_intervalId !== null) {
|
|
107
|
-
clearInterval(_intervalId);
|
|
108
|
-
_intervalId = null;
|
|
109
|
-
}
|
|
110
|
-
_set({ running: false });
|
|
111
|
-
stopFocusAudio();
|
|
112
|
-
}
|
|
113
|
-
function pomoSwitchMode(m) {
|
|
114
|
-
pomoPause();
|
|
115
|
-
_set({ mode: m, remaining: _durations[m], total: _durations[m] });
|
|
116
|
-
}
|
|
117
|
-
function _tick() {
|
|
118
|
-
if (_state.remaining <= 1) {
|
|
119
|
-
_onSessionEnd();
|
|
120
|
-
return;
|
|
121
|
-
}
|
|
122
|
-
_set({ remaining: _state.remaining - 1 });
|
|
123
|
-
}
|
|
124
|
-
function _onSessionEnd() {
|
|
125
|
-
if (_intervalId !== null) {
|
|
126
|
-
clearInterval(_intervalId);
|
|
127
|
-
_intervalId = null;
|
|
128
|
-
}
|
|
129
|
-
stopFocusAudio();
|
|
130
|
-
playAlarm(_alarm, { volume: _alarmVolume, repeat: _alarmRepeat });
|
|
131
|
-
const justFinishedFocus = _state.mode === "focus";
|
|
132
|
-
const headline = justFinishedFocus ? "Pomodoro complete \u2014 time for a break! \u{1F345}" : "Break's over \u2014 back to work!";
|
|
133
|
-
if (typeof Notification !== "undefined" && Notification.permission === "granted") {
|
|
134
|
-
try {
|
|
135
|
-
new Notification(headline);
|
|
136
|
-
} catch {
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
try {
|
|
140
|
-
toast_default.info(headline);
|
|
141
|
-
} catch {
|
|
142
|
-
}
|
|
143
|
-
if (_state.mode === "focus") {
|
|
144
|
-
const nextStreak = _state.streak + 1;
|
|
145
|
-
const newCount = _state.count + 1;
|
|
146
|
-
saveCount(newCount);
|
|
147
|
-
const nextMode = nextStreak % _behaviour.longBreakInterval === 0 ? "long" : "short";
|
|
148
|
-
_set({
|
|
149
|
-
running: false,
|
|
150
|
-
streak: nextStreak,
|
|
151
|
-
count: newCount,
|
|
152
|
-
mode: nextMode,
|
|
153
|
-
remaining: _durations[nextMode],
|
|
154
|
-
total: _durations[nextMode]
|
|
155
|
-
});
|
|
156
|
-
if (_behaviour.autoStartBreaks) setTimeout(() => pomoStart(), 50);
|
|
157
|
-
} else {
|
|
158
|
-
_set({
|
|
159
|
-
running: false,
|
|
160
|
-
mode: "focus",
|
|
161
|
-
remaining: _durations.focus,
|
|
162
|
-
total: _durations.focus
|
|
163
|
-
});
|
|
164
|
-
if (_behaviour.autoStartPomodoros) setTimeout(() => pomoStart(), 50);
|
|
165
|
-
}
|
|
166
|
-
}
|
|
167
|
-
function playAlarm(kind = _alarm, opts = {}) {
|
|
168
|
-
if (kind === "off") return;
|
|
169
|
-
const volScale = Math.max(0, Math.min(100, opts.volume ?? 100)) / 100;
|
|
170
|
-
if (volScale === 0) return;
|
|
171
|
-
const repeat = Math.max(1, Math.min(5, opts.repeat ?? 1));
|
|
172
|
-
for (let i = 0; i < repeat; i++) {
|
|
173
|
-
setTimeout(() => _playAlarmOnce(kind, volScale), i * 2500);
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
|
-
function _playAlarmOnce(kind, volScale) {
|
|
177
|
-
try {
|
|
178
|
-
const Ctor = window.AudioContext || window.webkitAudioContext;
|
|
179
|
-
if (!Ctor) return;
|
|
180
|
-
const ctx = new Ctor();
|
|
181
|
-
const playNote = (freq, start, duration, vol = 0.22, type = "sine") => {
|
|
182
|
-
const osc = ctx.createOscillator();
|
|
183
|
-
const gain = ctx.createGain();
|
|
184
|
-
osc.connect(gain);
|
|
185
|
-
gain.connect(ctx.destination);
|
|
186
|
-
osc.type = type;
|
|
187
|
-
osc.frequency.value = freq;
|
|
188
|
-
const t0 = ctx.currentTime + start;
|
|
189
|
-
gain.gain.setValueAtTime(0, t0);
|
|
190
|
-
gain.gain.linearRampToValueAtTime(vol * volScale, t0 + 0.03);
|
|
191
|
-
gain.gain.exponentialRampToValueAtTime(1e-4, t0 + duration);
|
|
192
|
-
osc.start(t0);
|
|
193
|
-
osc.stop(t0 + duration);
|
|
194
|
-
};
|
|
195
|
-
let totalDuration = 2;
|
|
196
|
-
if (kind === "bell") {
|
|
197
|
-
playNote(880, 0, 1.8);
|
|
198
|
-
playNote(1320, 0, 1.4, 0.1);
|
|
199
|
-
totalDuration = 2;
|
|
200
|
-
} else if (kind === "chime") {
|
|
201
|
-
playNote(659.25, 0, 0.7);
|
|
202
|
-
playNote(880, 0.2, 1.3);
|
|
203
|
-
totalDuration = 2;
|
|
204
|
-
} else if (kind === "bowl") {
|
|
205
|
-
playNote(440, 0, 3.4, 0.22);
|
|
206
|
-
playNote(660, 0, 3, 0.08);
|
|
207
|
-
playNote(880, 0.05, 2.8, 0.05);
|
|
208
|
-
totalDuration = 4;
|
|
209
|
-
} else if (kind === "wind-chimes") {
|
|
210
|
-
playNote(1175, 0, 1.1, 0.16);
|
|
211
|
-
playNote(880, 0.15, 1.3, 0.16);
|
|
212
|
-
playNote(1318, 0.3, 1.5, 0.16);
|
|
213
|
-
playNote(1047, 0.5, 1.7, 0.13);
|
|
214
|
-
totalDuration = 3;
|
|
215
|
-
}
|
|
216
|
-
setTimeout(() => {
|
|
217
|
-
try {
|
|
218
|
-
ctx.close();
|
|
219
|
-
} catch {
|
|
220
|
-
}
|
|
221
|
-
}, totalDuration * 1e3 + 500);
|
|
222
|
-
} catch {
|
|
223
|
-
}
|
|
224
|
-
}
|
|
225
|
-
var _focusAudio = null;
|
|
226
|
-
var FOCUS_VOL_CAP = {
|
|
227
|
-
none: 0,
|
|
228
|
-
white: 0.3,
|
|
229
|
-
pink: 0.3,
|
|
230
|
-
brown: 0.3,
|
|
231
|
-
"tick-fast": 0.6,
|
|
232
|
-
"tick-slow": 0.6,
|
|
233
|
-
rain: 0.4,
|
|
234
|
-
fireplace: 0.5
|
|
235
|
-
};
|
|
236
|
-
function _makeNoiseBuffer(ctx, type) {
|
|
237
|
-
if (type === "none") return null;
|
|
238
|
-
const sr = ctx.sampleRate;
|
|
239
|
-
const dur = type === "white" || type === "pink" || type === "brown" ? 2 : 4;
|
|
240
|
-
const len = sr * dur;
|
|
241
|
-
const buffer = ctx.createBuffer(1, len, sr);
|
|
242
|
-
const data = buffer.getChannelData(0);
|
|
243
|
-
if (type === "white") {
|
|
244
|
-
for (let i = 0; i < len; i++) data[i] = (Math.random() * 2 - 1) * 0.5;
|
|
245
|
-
} else if (type === "pink") {
|
|
246
|
-
let b0 = 0, b1 = 0, b2 = 0, b3 = 0, b4 = 0, b5 = 0, b6 = 0;
|
|
247
|
-
for (let i = 0; i < len; i++) {
|
|
248
|
-
const w = Math.random() * 2 - 1;
|
|
249
|
-
b0 = 0.99886 * b0 + w * 0.0555179;
|
|
250
|
-
b1 = 0.99332 * b1 + w * 0.0750759;
|
|
251
|
-
b2 = 0.969 * b2 + w * 0.153852;
|
|
252
|
-
b3 = 0.8665 * b3 + w * 0.3104856;
|
|
253
|
-
b4 = 0.55 * b4 + w * 0.5329522;
|
|
254
|
-
b5 = -0.7616 * b5 - w * 0.016898;
|
|
255
|
-
data[i] = (b0 + b1 + b2 + b3 + b4 + b5 + b6 + w * 0.5362) * 0.11 * 0.55;
|
|
256
|
-
b6 = w * 0.115926;
|
|
257
|
-
}
|
|
258
|
-
} else if (type === "brown") {
|
|
259
|
-
let last = 0;
|
|
260
|
-
for (let i = 0; i < len; i++) {
|
|
261
|
-
const w = Math.random() * 2 - 1;
|
|
262
|
-
last = (last + 0.02 * w) / 1.02;
|
|
263
|
-
data[i] = last * 3.5 * 0.5;
|
|
264
|
-
}
|
|
265
|
-
} else if (type === "tick-fast" || type === "tick-slow") {
|
|
266
|
-
const intervalSec = type === "tick-fast" ? 0.5 : 1;
|
|
267
|
-
const tickSamples = Math.floor(sr * 0.045);
|
|
268
|
-
for (let t = 0; t < dur; t += intervalSec) {
|
|
269
|
-
const start = Math.floor(t * sr);
|
|
270
|
-
for (let i = 0; i < tickSamples && start + i < len; i++) {
|
|
271
|
-
const env = Math.exp(-i / sr * 180);
|
|
272
|
-
const noise = Math.random() * 2 - 1;
|
|
273
|
-
const tone = Math.sin(2 * Math.PI * 1100 * (i / sr));
|
|
274
|
-
data[start + i] += (noise * 0.7 + tone * 0.25) * env * 0.55;
|
|
275
|
-
}
|
|
276
|
-
}
|
|
277
|
-
} else if (type === "rain") {
|
|
278
|
-
let prev = 0;
|
|
279
|
-
for (let i = 0; i < len; i++) {
|
|
280
|
-
const w = Math.random() * 2 - 1;
|
|
281
|
-
const filtered = w - prev * 0.93;
|
|
282
|
-
prev = w;
|
|
283
|
-
const gust = 0.7 + 0.3 * Math.sin(i / sr * 2 * Math.PI * 0.25);
|
|
284
|
-
data[i] = filtered * gust * 0.4;
|
|
285
|
-
}
|
|
286
|
-
} else if (type === "fireplace") {
|
|
287
|
-
let last = 0;
|
|
288
|
-
for (let i = 0; i < len; i++) {
|
|
289
|
-
const w = Math.random() * 2 - 1;
|
|
290
|
-
last = (last + 0.02 * w) / 1.02;
|
|
291
|
-
data[i] = last * 1.6;
|
|
292
|
-
}
|
|
293
|
-
let next = Math.random() * 0.4 * sr;
|
|
294
|
-
while (next < len) {
|
|
295
|
-
const popLen = Math.floor((0.012 + Math.random() * 0.05) * sr);
|
|
296
|
-
const popVol = 0.35 + Math.random() * 0.45;
|
|
297
|
-
const popPos = Math.floor(next);
|
|
298
|
-
for (let i = 0; i < popLen && popPos + i < len; i++) {
|
|
299
|
-
const env = Math.exp(-i / sr * 90);
|
|
300
|
-
data[popPos + i] += (Math.random() * 2 - 1) * env * popVol;
|
|
301
|
-
}
|
|
302
|
-
next += (0.08 + Math.random() * 0.62) * sr;
|
|
303
|
-
}
|
|
304
|
-
}
|
|
305
|
-
return buffer;
|
|
306
|
-
}
|
|
307
|
-
function startFocusAudio() {
|
|
308
|
-
if (_focusAudio) return;
|
|
309
|
-
if (_focusSoundType === "none" || _focusVolume === 0) return;
|
|
310
|
-
try {
|
|
311
|
-
const Ctor = window.AudioContext || window.webkitAudioContext;
|
|
312
|
-
if (!Ctor) return;
|
|
313
|
-
const ctx = new Ctor();
|
|
314
|
-
const buffer = _makeNoiseBuffer(ctx, _focusSoundType);
|
|
315
|
-
if (!buffer) {
|
|
316
|
-
try {
|
|
317
|
-
ctx.close();
|
|
318
|
-
} catch {
|
|
319
|
-
}
|
|
320
|
-
return;
|
|
321
|
-
}
|
|
322
|
-
const src = ctx.createBufferSource();
|
|
323
|
-
src.buffer = buffer;
|
|
324
|
-
src.loop = true;
|
|
325
|
-
const gain = ctx.createGain();
|
|
326
|
-
gain.gain.value = _focusVolume / 100 * FOCUS_VOL_CAP[_focusSoundType];
|
|
327
|
-
src.connect(gain).connect(ctx.destination);
|
|
328
|
-
src.start();
|
|
329
|
-
_focusAudio = { ctx, src, gain };
|
|
330
|
-
} catch {
|
|
331
|
-
}
|
|
332
|
-
}
|
|
333
|
-
function stopFocusAudio() {
|
|
334
|
-
if (!_focusAudio) return;
|
|
335
|
-
try {
|
|
336
|
-
_focusAudio.src.stop();
|
|
337
|
-
} catch {
|
|
338
|
-
}
|
|
339
|
-
try {
|
|
340
|
-
_focusAudio.ctx.close();
|
|
341
|
-
} catch {
|
|
342
|
-
}
|
|
343
|
-
_focusAudio = null;
|
|
344
|
-
}
|
|
345
|
-
function previewFocusSound(type, volume) {
|
|
346
|
-
if (type === "none" || volume === 0) return;
|
|
347
|
-
try {
|
|
348
|
-
const Ctor = window.AudioContext || window.webkitAudioContext;
|
|
349
|
-
if (!Ctor) return;
|
|
350
|
-
const ctx = new Ctor();
|
|
351
|
-
const buffer = _makeNoiseBuffer(ctx, type);
|
|
352
|
-
if (!buffer) {
|
|
353
|
-
try {
|
|
354
|
-
ctx.close();
|
|
355
|
-
} catch {
|
|
356
|
-
}
|
|
357
|
-
return;
|
|
358
|
-
}
|
|
359
|
-
const src = ctx.createBufferSource();
|
|
360
|
-
src.buffer = buffer;
|
|
361
|
-
src.loop = true;
|
|
362
|
-
const gain = ctx.createGain();
|
|
363
|
-
gain.gain.value = volume / 100 * FOCUS_VOL_CAP[type];
|
|
364
|
-
src.connect(gain).connect(ctx.destination);
|
|
365
|
-
src.start();
|
|
366
|
-
setTimeout(() => {
|
|
367
|
-
try {
|
|
368
|
-
src.stop();
|
|
369
|
-
} catch {
|
|
370
|
-
}
|
|
371
|
-
try {
|
|
372
|
-
ctx.close();
|
|
373
|
-
} catch {
|
|
374
|
-
}
|
|
375
|
-
}, 3e3);
|
|
376
|
-
} catch {
|
|
377
|
-
}
|
|
378
|
-
}
|
|
379
|
-
var POMODORO_LEGACY_KEY = "pomodoro_tasks";
|
|
380
|
-
var POMODORO_LEGACY_MIGRATED_FLAG = "pomodoro_tasks_migrated";
|
|
381
|
-
function uid() {
|
|
382
|
-
return Math.random().toString(36).slice(2, 11);
|
|
383
|
-
}
|
|
384
|
-
function nowIso() {
|
|
385
|
-
return (/* @__PURE__ */ new Date()).toISOString();
|
|
386
|
-
}
|
|
387
|
-
var provider = null;
|
|
388
|
-
var cache = [];
|
|
389
|
-
var loaded = false;
|
|
390
|
-
var inflight = null;
|
|
391
|
-
var listeners = /* @__PURE__ */ new Set();
|
|
392
|
-
function emit() {
|
|
393
|
-
for (const l of listeners) l();
|
|
394
|
-
}
|
|
395
|
-
function setCache(next) {
|
|
396
|
-
cache = next;
|
|
397
|
-
emit();
|
|
398
|
-
}
|
|
399
|
-
function refresh() {
|
|
400
|
-
const p = provider;
|
|
401
|
-
if (!p) {
|
|
402
|
-
cache = [];
|
|
403
|
-
loaded = true;
|
|
404
|
-
emit();
|
|
405
|
-
return Promise.resolve();
|
|
406
|
-
}
|
|
407
|
-
inflight = p.list().then((rows) => {
|
|
408
|
-
if (provider === p) {
|
|
409
|
-
cache = rows;
|
|
410
|
-
loaded = true;
|
|
411
|
-
emit();
|
|
412
|
-
}
|
|
413
|
-
}).catch(() => {
|
|
414
|
-
if (provider === p) {
|
|
415
|
-
loaded = true;
|
|
416
|
-
emit();
|
|
417
|
-
}
|
|
418
|
-
}).finally(() => {
|
|
419
|
-
inflight = null;
|
|
420
|
-
});
|
|
421
|
-
return inflight;
|
|
422
|
-
}
|
|
423
|
-
function setShellTodoProvider(next) {
|
|
424
|
-
provider = next;
|
|
425
|
-
cache = [];
|
|
426
|
-
loaded = false;
|
|
427
|
-
if (next) refresh();
|
|
428
|
-
else emit();
|
|
429
|
-
}
|
|
430
|
-
function hasShellTodoProvider() {
|
|
431
|
-
return provider !== null;
|
|
432
|
-
}
|
|
433
|
-
function subscribe(cb) {
|
|
434
|
-
listeners.add(cb);
|
|
435
|
-
if (provider && !loaded && !inflight) refresh();
|
|
436
|
-
return () => {
|
|
437
|
-
listeners.delete(cb);
|
|
438
|
-
};
|
|
439
|
-
}
|
|
440
|
-
function getSnapshot() {
|
|
441
|
-
return cache;
|
|
442
|
-
}
|
|
443
|
-
function usePrefsTodoTasks() {
|
|
444
|
-
const { prefs, save } = useShellPrefs();
|
|
445
|
-
const tasks = useMemo(() => {
|
|
446
|
-
const raw = prefs.todo_tasks;
|
|
447
|
-
return Array.isArray(raw) ? raw : [];
|
|
448
|
-
}, [prefs.todo_tasks]);
|
|
449
|
-
const writeTasks = useCallback((next) => {
|
|
450
|
-
save({ todo_tasks: next });
|
|
451
|
-
}, [save]);
|
|
452
|
-
const addTask = useCallback((input) => {
|
|
453
|
-
const id = uid();
|
|
454
|
-
const ts = nowIso();
|
|
455
|
-
const task = { done: false, ...input, name: input.name.trim(), id, createdAt: ts, updatedAt: ts };
|
|
456
|
-
writeTasks([...tasks, task]);
|
|
457
|
-
return id;
|
|
458
|
-
}, [tasks, writeTasks]);
|
|
459
|
-
const updateTask = useCallback((id, patch) => {
|
|
460
|
-
writeTasks(tasks.map((t) => t.id === id ? { ...t, ...patch, id: t.id, updatedAt: nowIso() } : t));
|
|
461
|
-
}, [tasks, writeTasks]);
|
|
462
|
-
const removeTask = useCallback((id) => {
|
|
463
|
-
writeTasks(tasks.filter((t) => t.id !== id));
|
|
464
|
-
}, [tasks, writeTasks]);
|
|
465
|
-
const toggleDone = useCallback((id) => {
|
|
466
|
-
const target = tasks.find((t) => t.id === id);
|
|
467
|
-
if (target) updateTask(id, { done: !target.done });
|
|
468
|
-
}, [tasks, updateTask]);
|
|
469
|
-
return { tasks, addTask, updateTask, removeTask, toggleDone, setAllTasks: writeTasks };
|
|
470
|
-
}
|
|
471
|
-
function useTodoTasks() {
|
|
472
|
-
const prefsImpl = usePrefsTodoTasks();
|
|
473
|
-
const providerTasks = useSyncExternalStore(subscribe, getSnapshot, getSnapshot);
|
|
474
|
-
const addTask = useCallback((input) => {
|
|
475
|
-
const p = provider;
|
|
476
|
-
if (!p) return prefsImpl.addTask(input);
|
|
477
|
-
const tempId = "tmp-" + uid();
|
|
478
|
-
const ts = nowIso();
|
|
479
|
-
const optimistic = { done: false, ...input, name: input.name.trim(), id: tempId, createdAt: ts, updatedAt: ts };
|
|
480
|
-
setCache([...cache, optimistic]);
|
|
481
|
-
p.create({ ...input, name: input.name.trim() }).then((saved) => setCache(cache.map((t) => t.id === tempId ? { ...optimistic, ...saved } : t))).catch(() => setCache(cache.filter((t) => t.id !== tempId)));
|
|
482
|
-
return tempId;
|
|
483
|
-
}, [prefsImpl]);
|
|
484
|
-
const updateTask = useCallback((id, patch) => {
|
|
485
|
-
const p = provider;
|
|
486
|
-
if (!p) return prefsImpl.updateTask(id, patch);
|
|
487
|
-
setCache(cache.map((t) => t.id === id ? { ...t, ...patch, id, updatedAt: nowIso() } : t));
|
|
488
|
-
p.update(id, patch).catch(() => {
|
|
489
|
-
refresh();
|
|
490
|
-
});
|
|
491
|
-
}, [prefsImpl]);
|
|
492
|
-
const removeTask = useCallback((id) => {
|
|
493
|
-
const p = provider;
|
|
494
|
-
if (!p) return prefsImpl.removeTask(id);
|
|
495
|
-
const prev = cache;
|
|
496
|
-
setCache(cache.filter((t) => t.id !== id));
|
|
497
|
-
p.remove(id).catch(() => setCache(prev));
|
|
498
|
-
}, [prefsImpl]);
|
|
499
|
-
const toggleDone = useCallback((id) => {
|
|
500
|
-
if (!provider) return prefsImpl.toggleDone(id);
|
|
501
|
-
const target = cache.find((t) => t.id === id);
|
|
502
|
-
if (target) updateTask(id, { done: !target.done });
|
|
503
|
-
}, [prefsImpl, updateTask]);
|
|
504
|
-
const setAllTasks = useCallback((next) => {
|
|
505
|
-
if (!provider) prefsImpl.setAllTasks(next);
|
|
506
|
-
}, [prefsImpl]);
|
|
507
|
-
if (!hasShellTodoProvider()) return prefsImpl;
|
|
508
|
-
return { tasks: providerTasks, addTask, updateTask, removeTask, toggleDone, setAllTasks };
|
|
509
|
-
}
|
|
510
|
-
function migratePomodoroTasksOnce(currentTasks, setAllTasks) {
|
|
511
|
-
try {
|
|
512
|
-
if (localStorage.getItem(POMODORO_LEGACY_MIGRATED_FLAG)) return;
|
|
513
|
-
const raw = localStorage.getItem(POMODORO_LEGACY_KEY);
|
|
514
|
-
if (!raw) {
|
|
515
|
-
localStorage.setItem(POMODORO_LEGACY_MIGRATED_FLAG, "1");
|
|
516
|
-
return;
|
|
517
|
-
}
|
|
518
|
-
const legacy = JSON.parse(raw);
|
|
519
|
-
if (!Array.isArray(legacy) || legacy.length === 0) {
|
|
520
|
-
localStorage.removeItem(POMODORO_LEGACY_KEY);
|
|
521
|
-
localStorage.setItem(POMODORO_LEGACY_MIGRATED_FLAG, "1");
|
|
522
|
-
return;
|
|
523
|
-
}
|
|
524
|
-
const ts = nowIso();
|
|
525
|
-
const migrated = legacy.filter((t) => typeof t?.name === "string").map((t) => ({
|
|
526
|
-
id: t.id || uid(),
|
|
527
|
-
name: String(t.name),
|
|
528
|
-
done: !!t.done,
|
|
529
|
-
estimated: typeof t.estimated === "number" ? t.estimated : void 0,
|
|
530
|
-
completed: typeof t.completed === "number" ? t.completed : void 0,
|
|
531
|
-
createdAt: ts,
|
|
532
|
-
updatedAt: ts
|
|
533
|
-
}));
|
|
534
|
-
const existingIds = new Set(currentTasks.map((t) => t.id));
|
|
535
|
-
const additions = migrated.filter((t) => !existingIds.has(t.id));
|
|
536
|
-
setAllTasks([...additions, ...currentTasks]);
|
|
537
|
-
localStorage.removeItem(POMODORO_LEGACY_KEY);
|
|
538
|
-
localStorage.setItem(POMODORO_LEGACY_MIGRATED_FLAG, "1");
|
|
539
|
-
} catch {
|
|
540
|
-
try {
|
|
541
|
-
localStorage.setItem(POMODORO_LEGACY_MIGRATED_FLAG, "1");
|
|
542
|
-
} catch {
|
|
543
|
-
}
|
|
544
|
-
}
|
|
545
|
-
}
|
|
546
|
-
|
|
547
|
-
export { ALARM_OPTIONS, FOCUS_SOUND_OPTIONS, getPomoSnapshot, migratePomodoroTasksOnce, playAlarm, pomoPause, pomoStart, pomoSwitchMode, previewFocusSound, setPomoAlarm, setPomoAlarmConfig, setPomoBehaviour, setPomoDurations, setPomoFocusSound, setShellTodoProvider, subscribePomo, useTodoTasks };
|
|
548
|
-
//# sourceMappingURL=chunk-SHQM5CK3.js.map
|
|
549
|
-
//# sourceMappingURL=chunk-SHQM5CK3.js.map
|