EXAMPLE.md

cat EXAMPLE.md
/example
<!--
  This file is also the source for the docs site's EXAMPLE.md tab.
  The comments are valid erza source comments and are ignored by the compiler.
-->
<Screen title="Koinonia">
  <!-- Splash runs before the main screen and is useful for app identity. -->
  <Splash duration-ms="1400">
    <!-- SplashAnimation is an unboxed ASCII frame animation. -->
    <SplashAnimation fps="7">
      <Frame>
 _  __      _                       _
| |/ /___  (_)___  ____  ____  ____(_)_ _
|   / __ \/ / __ \/ __ \/ __ \/ __/ /  ' \
|   / /_/ / / / / / /_/ / / / / /_/ / /| |
|_|\_\____/_/_/ /_/\____/_/ /_/\__/_/_/ |_|

terminal social commons .
      </Frame>
      <Frame>
 _  __      _                       _
| |/ /___  (_)___  ____  ____  ____(_)_ _
|   / __ \/ / __ \/ __ \/ __ \/ __/ /  ' \
|   / /_/ / / / / / /_/ / / / / /_/ / /| |
|_|\_\____/_/_/ /_/\____/_/ /_/\__/_/_/ |_|

terminal social commons ..
      </Frame>
      <Frame>
 _  __      _                       _
| |/ /___  (_)___  ____  ____  ____(_)_ _
|   / __ \/ / __ \/ __ \/ __ \/ __/ /  ' \
|   / /_/ / / / / / /_/ / / / / /_/ / /| |
|_|\_\____/_/_/ /_/\____/_/ /_/\__/_/_/ |_|

terminal social commons ...
      </Frame>
    </SplashAnimation>
  </Splash>

  <!-- backend(...) pulls read-side data into the template scope. -->
  <? auth = backend("auth.viewer") ?>
  <? status = backend("ui.status") ?>
  <? overview = backend("network.overview") ?>
  <? highlights = backend("mission.highlights") ?>

  <!-- PHP-style template delimiters drive branching and loops. -->
  <? if auth.logged_in ?>
    <? profile = backend("profiles.current") ?>
    <? timeline = backend("feed.timeline") ?>

    <!-- Top-level Section blocks are app tabs. -->
    <Section title="Feed" tab-order="1" default-tab="true">
      <Header>Town Square</Header>
      <Text><?= status ?></Text>

      <!-- ButtonRow is the standard horizontal action strip. -->
      <ButtonRow>
        <!-- ui.open_modal is handled by the runtime, not the backend. -->
        <Action on:press="ui.open_modal" modal:id="create-post">New post</Action>
      </ButtonRow>

      <Text><?= overview.posts ?> posts, <?= overview.replies ?> replies, and <?= overview.people ?> residents are live in the square.</Text>

      <? if timeline ?>
        <? for post in timeline ?>
          <!-- Nested Section blocks become boxed content panels. -->
          <Section title="@<?= post.handle ?>">
            <Text><?= post.body ?></Text>
            <Text><?= post.likes ?> likes | <?= post.reply_count ?> replies</Text>

            <ButtonRow align="right">
              <!-- Non-ui action names are backend commands. -->
              <Action on:press="feed.like" post:id="<?= post.id ?>">Like</Action>
              <Action on:press="ui.open_modal" modal:id="feed-thread-<?= post.id ?>">View Replies</Action>
              <Action on:press="ui.open_modal" modal:id="feed-compose-post-<?= post.id ?>">Reply</Action>
            </ButtonRow>
          </Section>
        <? endfor ?>
      <? else ?>
        <Text>No posts yet. Open the modal above and start the square.</Text>
      <? endif ?>
    </Section>

    <Section title="Profile" tab-order="0">
      <!-- AsciiArt preserves whitespace exactly, which is ideal for profile pictures. -->
      <AsciiArt><?= profile.picture ?></AsciiArt>
      <Header>@<?= profile.handle ?></Header>
      <Text><?= profile.description or "No description set yet." ?></Text>

      <ButtonRow>
        <Action on:press="ui.open_modal" modal:id="create-post">New post</Action>
        <Action on:press="ui.open_modal" modal:id="profile-edit">Edit profile</Action>
      </ButtonRow>

      <Text><?= status ?></Text>

      <? if profile.posts ?>
        <? for post in profile.posts ?>
          <Section title="@<?= post.handle ?>">
            <Text><?= post.body ?></Text>
            <Text><?= post.likes ?> likes | <?= post.reply_count ?> replies</Text>

            <ButtonRow align="right">
              <Action on:press="feed.like" post:id="<?= post.id ?>">Like</Action>
              <Action on:press="ui.open_modal" modal:id="profile-thread-<?= post.id ?>">View Replies</Action>
              <Action on:press="ui.open_modal" modal:id="profile-compose-post-<?= post.id ?>">Reply</Action>
            </ButtonRow>
          </Section>
        <? endfor ?>
      <? else ?>
        <Text>No posts yet. Open the modal above and start your thread history.</Text>
      <? endif ?>
    </Section>

    <!-- Direct-action tabs are valid when the tab triggers behavior immediately. -->
    <Section title="Logout" tab-order="2">
      <Action on:press="auth.logout">Log out</Action>
    </Section>

    <? for post in timeline ?>
      <!-- View modals may contain read-only content and buttons that open form-only modals. -->
      <Modal id="feed-thread-<?= post.id ?>" title="Replies for @<?= post.handle ?>">
        <Header>@<?= post.handle ?></Header>
        <Text><?= post.body ?></Text>
        <Text><?= post.likes ?> likes | <?= post.reply_count ?> replies</Text>

        <? if post.replies ?>
          <? for reply in post.replies ?>
            <Section title="@<?= reply.handle ?>">
              <Text><?= reply.body ?></Text>
              <Text><?= reply.likes ?> likes | <?= reply.reply_count ?> replies</Text>

              <? for nested in reply.replies ?>
                <Section title="@<?= nested.handle ?>">
                  <Text><?= nested.body ?></Text>
                  <Text><?= nested.likes ?> likes</Text>
                </Section>
              <? endfor ?>

              <ButtonRow align="right">
                <Action on:press="ui.open_modal" modal:id="feed-compose-reply-<?= reply.id ?>">Reply on Thread</Action>
              </ButtonRow>
            </Section>
          <? endfor ?>
        <? else ?>
          <Text>No replies yet.</Text>
        <? endif ?>
      </Modal>

      <!-- Form modals contain exactly one Form. -->
      <Modal id="feed-compose-post-<?= post.id ?>" title="Reply">
        <Form action="/threads/reply">
          <Header>@<?= post.handle ?></Header>
          <Text><?= post.body ?></Text>
          <Text><?= post.likes ?> likes | <?= post.reply_count ?> replies</Text>

          <!-- Hidden inputs pass thread state without rendering visible fields. -->
          <Input name="thread_slug" type="hidden" value="<?= post.slug ?>" />
          <Input name="body" type="text" label="Reply" required="mandatory" />

          <!-- Inside forms, ButtonRow contains Submit buttons. -->
          <ButtonRow align="right">
            <Submit>Post reply</Submit>
          </ButtonRow>
        </Form>
      </Modal>

      <? for reply in post.replies ?>
        <!-- Reply-on-reply shows boxed context before the actual form fields. -->
        <Modal id="feed-compose-reply-<?= reply.id ?>" title="Reply on Thread">
          <Form action="/threads/reply">
            <Section title="@<?= post.handle ?>">
              <Text><?= post.body ?></Text>
              <Text><?= post.likes ?> likes | <?= post.reply_count ?> replies</Text>

              <Section title="@<?= reply.handle ?>">
                <Text><?= reply.body ?></Text>
                <Text><?= reply.likes ?> likes | <?= reply.reply_count ?> replies</Text>
              </Section>
            </Section>

            <Input name="thread_slug" type="hidden" value="<?= post.slug ?>" />
            <Input name="parent_reply_id" type="hidden" value="<?= reply.id ?>" />
            <Input name="body" type="text" label="Reply" required="mandatory" />
            <ButtonRow align="right">
              <Submit>Post reply</Submit>
            </ButtonRow>
          </Form>
        </Modal>
      <? endfor ?>
    <? endfor ?>

    <!-- The Profile tab mirrors much of the Feed thread UI with profile-scoped modal ids. -->
    <? for post in profile.posts ?>
      <Modal id="profile-thread-<?= post.id ?>" title="Replies for @<?= post.handle ?>">
        <Header>@<?= post.handle ?></Header>
        <Text><?= post.body ?></Text>
        <Text><?= post.likes ?> likes | <?= post.reply_count ?> replies</Text>

        <? if post.replies ?>
          <? for reply in post.replies ?>
            <Section title="@<?= reply.handle ?>">
              <Text><?= reply.body ?></Text>
              <Text><?= reply.likes ?> likes | <?= reply.reply_count ?> replies</Text>

              <? for nested in reply.replies ?>
                <Section title="@<?= nested.handle ?>">
                  <Text><?= nested.body ?></Text>
                  <Text><?= nested.likes ?> likes</Text>
                </Section>
              <? endfor ?>

              <ButtonRow align="right">
                <Action on:press="ui.open_modal" modal:id="profile-compose-reply-<?= reply.id ?>">Reply on Thread</Action>
              </ButtonRow>
            </Section>
          <? endfor ?>
        <? else ?>
          <Text>No replies yet.</Text>
        <? endif ?>
      </Modal>

      <Modal id="profile-compose-post-<?= post.id ?>" title="Reply">
        <Form action="/threads/reply">
          <Header>@<?= post.handle ?></Header>
          <Text><?= post.body ?></Text>
          <Text><?= post.likes ?> likes | <?= post.reply_count ?> replies</Text>
          <Input name="thread_slug" type="hidden" value="<?= post.slug ?>" />
          <Input name="body" type="text" label="Reply" required="mandatory" />
          <ButtonRow align="right">
            <Submit>Post reply</Submit>
          </ButtonRow>
        </Form>
      </Modal>

      <? for reply in post.replies ?>
        <Modal id="profile-compose-reply-<?= reply.id ?>" title="Reply on Thread">
          <Form action="/threads/reply">
            <Section title="@<?= post.handle ?>">
              <Text><?= post.body ?></Text>
              <Text><?= post.likes ?> likes | <?= post.reply_count ?> replies</Text>

              <Section title="@<?= reply.handle ?>">
                <Text><?= reply.body ?></Text>
                <Text><?= reply.likes ?> likes | <?= reply.reply_count ?> replies</Text>
              </Section>
            </Section>
            <Input name="thread_slug" type="hidden" value="<?= post.slug ?>" />
            <Input name="parent_reply_id" type="hidden" value="<?= reply.id ?>" />
            <Input name="body" type="text" label="Reply" required="mandatory" />
            <ButtonRow align="right">
              <Submit>Post reply</Submit>
            </ButtonRow>
          </Form>
        </Modal>
      <? endfor ?>
    <? endfor ?>

    <!-- Edit profile shows both a plain text input and an ascii-art input. -->
    <Modal id="profile-edit" title="Edit Profile">
      <Form action="/profile/edit">
        <Input name="description" type="text" label="Description" value="<?= profile.description ?>" />
        <Input name="profile_picture" type="ascii-art" label="Profile Picture" value="<?= profile.picture ?>" />
        <ButtonRow align="right">
          <Submit>Save profile</Submit>
        </ButtonRow>
      </Form>
    </Modal>

    <Modal id="create-post" title="New Post">
      <Form action="/posts">
        <Input name="body" type="text" label="Post" required="mandatory" />
        <ButtonRow align="right">
          <Submit>Post to Koinonia</Submit>
        </ButtonRow>
      </Form>
    </Modal>

  <? else ?>
    <!-- Logged-out users get a different tab set, driven by the same file. -->
    <Section title="Why Koinonia">
      <Header>One terminal-native town square.</Header>
      <Text><?= overview.posts ?> posts, <?= overview.replies ?> replies, and <?= overview.people ?> residents are already live.</Text>

      <? for highlight in highlights ?>
        <Text><?= highlight.title ?></Text>
        <Text><?= highlight.body ?></Text>
      <? endfor ?>
    </Section>

    <Section title="Login / Sign Up">
      <Action on:press="ui.open_modal" modal:id="auth-access">Open account access</Action>
    </Section>

    <Modal id="auth-access" title="Login / Sign Up">
      <Form action="/auth/access">
        <Input name="username" type="text" label="Username" required="mandatory" />
        <Input name="password" type="password" label="Password" required="mandatory" />
        <ButtonRow align="right">
          <Submit>Enter Koinonia</Submit>
        </ButtonRow>
      </Form>
    </Modal>
  <? endif ?>
</Screen>