still-free.openapps.xyz

Source

This app’s code and revision history are public. Download a copy or explore the files below.

Public
The app’s code and revision history are public.
Owned app · rev 0fa0e84d537b
Run it yourself
Take the whole tree and run it on your own machine. The download needs no account. Cloning needs a sign-in.
Download .zip
bounded clone a8c677472ab5691741798a3d
A copy you download is not bounded. The guarantees this app runs under - declared egress, proven invariants, writes that fail closed - live in the runtime serving this page, not in the files. What you get is auditable source you can read and run, with no runtime guarantees attached.
← All files
src/Today.tsx
// Today: the app's home. A one minute breath, a few sessions that suit the time of day, and how
// the practice is going.
import { SESSIONS } from "./content/sessions";
import { STORIES, storyMinutes } from "./content/stories";
import { useProgress } from "./lib/progress";
import { A, Icon } from "./ui";

function picks(hour: number): string[] {
  if (hour < 5) return ["falling-asleep", "body-scan"];
  if (hour < 11) return ["morning-start", "breath-focus"];
  if (hour < 17) return ["focus-before-work", "three-minute-reset"];
  if (hour < 21) return ["stress-relief", "gratitude"];
  return ["falling-asleep", "body-scan"];
}

export function Today() {
  const p = useProgress();
  const now = new Date();
  const hour = now.getHours();
  const greeting = hour < 5 ? "Still up?" : hour < 12 ? "Good morning." : hour < 18 ? "Good afternoon." : "Good evening.";
  const sessions = picks(hour).map((slug) => SESSIONS.find((s) => s.slug === slug)!);
  const story = STORIES[now.getDate() % STORIES.length];
  return (
    <div className="page wrap">
      <header className="page-head">
        <p className="eyebrow">{now.toLocaleDateString(undefined, { weekday: "long", month: "long", day: "numeric" })}</p>
        <h1 className="page-title">{greeting}</h1>
      </header>

      <A className="stats-strip" href="/progress" aria-label="Your progress">
        <span><strong>{p.streak}</strong> day streak</span>
        <span><strong>{p.minutes}</strong> minutes</span>
        <span><strong>{p.sessions}</strong> sessions</span>
      </A>

      <div className="today-grid">
        <section className="breath-card card" aria-labelledby="minute">
          <div className="orb" aria-hidden="true" />
          <div>
            <h2 className="card-title" id="minute">Take a minute</h2>
            <p className="muted">One minute of box breathing: in for four, hold for four, out for four, hold for four.</p>
          </div>
          <A className="btn btn-lg" href="/breathe/box?min=1">Begin</A>
        </section>

        <section aria-labelledby="now">
          <h2 className="card-title" id="now">For right now</h2>
          <ul className="card-list">
            {sessions.map((s) => (
              <li key={s.slug}>
                <A className="item-card" href={`/meditate/${s.slug}`}>
                  <span className="item-main">
                    <span className="item-title">{s.title}</span>
                    <span className="item-meta">{s.lengths[0]} min</span>
                    <span className="item-text">{s.summary}</span>
                  </span>
                  <span className="item-go" aria-hidden="true"><Icon name="play" size={16} /></span>
                </A>
              </li>
            ))}
            <li>
              <A className="item-card night-card" href={`/sleep/${story.slug}`}>
                <span className="item-main">
                  <span className="item-title">{story.title}</span>
                  <span className="item-meta">Sleep story · {storyMinutes(story)} min</span>
                  <span className="item-text">{story.summary}</span>
                </span>
                <span className="item-go" aria-hidden="true"><Icon name="moon" size={16} /></span>
              </A>
            </li>
          </ul>
        </section>
      </div>

      <h2 className="section-title">Everything in Still</h2>
      <ul className="tiles">
        <li><A className="tile" href="/breathe"><Icon name="breathe" /><strong>Breathe</strong><span>Box, 4-7-8, coherent, your own</span></A></li>
        <li><A className="tile" href="/meditate"><Icon name="meditate" /><strong>Meditate</strong><span>12 guided sessions and a timer</span></A></li>
        <li><A className="tile" href="/sounds"><Icon name="sounds" /><strong>Sounds</strong><span>Rain, ocean, fire, white noise</span></A></li>
        <li><A className="tile" href="/sleep"><Icon name="sleep" /><strong>Sleep</strong><span>Stories and a sleep timer</span></A></li>
      </ul>
    </div>
  );
}

Change history

Link to OpenApps pages and add a contribution strip
0fa0e84d53 · 19 hours ago
Bind the agent address in the policy
6f3baa1c72 · 1 day ago
Add favicon.ico so browsers that ask for it stop getting a 404
1a004fe0e3 · 1 day ago
Bounded source sync
afe642fe50 · 2 days ago
Bounded source sync
2c581f55ea · 2 days ago
Bounded source sync
375934c28b · 2 days ago
Bounded source sync
74ff37d51a · 2 days ago