Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

💬 Discussions Epic 💬 #116

Open
wants to merge 14 commits into
base: master
Choose a base branch
from
Open

💬 Discussions Epic 💬 #116

wants to merge 14 commits into from

Conversation

rtshkmr
Copy link
Member

@rtshkmr rtshkmr commented Oct 9, 2024

No description provided.

* Add generic debug dump component

This makes life easy when wiring things up

* Rename namespace for Context.Read.*

* Groundwork: add discuss component w sheafs

* Init Context.Components mod for common components

* Add skeletons for Sheaf Container

Container managers sheaf state within itself.
Should actually make the verse-matrix use this container, sometime.

* Minor changes, add some TODOs to share

explicit todos

Minor change

* Add live component EditableMarkDisplay

* Add UI improvements to EditableMarkDisplay

The edit button on quick draft should only be seen when the dropdown is
expanded and all the marks can be seen. The general pattern I'm trying
to follow is that buttons should only be shown when an action makes
sense. So here, if the user can't even see the marks currently
accumulating, then the user shouldn't have the chance to edit any marks.

Notice that the EditableMarkDisplay is a live_component that is a child
of a function component (collapsible_marks_display). This is so that it can keep its own state and
do it's own event-handling. I'm not sure if this is pattern-breaking.
A reference to the actual parent live_component that calls collapsible_marks_display
will always be there in case there's a need for the parent to handle
any particular events. So comms b/w live_components is still going to be
via phx-target values.

* Change <input/> -> <textarea/> fr quick_draft_form

* Add tailwind config for custom svg icons

not sure how the scaling for this works, seems like i can't just put in
the class="h-5 w-5" to do the scaling

* Let custom svg be scalable

* Subtly shift the ping indicator to control panel

* Marks ordering in Sheaf and L-Trees  (#114)

* do sheafs grow on trees

* sangh session dealing with lineage

* Solve initial order problem

* fix: ensure non-null id used @ EditableMarkDisplay

---------

Co-authored-by: ks0m1c_dharma <[email protected]>

* Trigger Diff

* TOMBSTONING

* Fix bugs and revert ui for read_mode:delete marks

1.  JIT generate id for marks yet to be inserted to the db: instead of
    using a temp id, I'm actually assigning a JIT-generated id for a
    mark even if that isn't inserted into the db yet. this has two
    benefits: div ids have meaningful static ids (e.g.
    mark-container-\<\> mark.id) regardless of whether that mark has
    been inserted into the db or not. While doing this, the changeset
    for marks has been udpated to add id as well. This fixes a bunch of
    id-based errors as well.

2.  while doing 1, it came to light that the bindHoverune handlers were
    not handling the draft mark update properly (i.e. not using the
    already existing update function in mark) . it's changed now,
    example of the diff:

    ``` diff
      @impl true
      def handle_event(
            "bindHoveRune",
            %{"binding" => bind = %{"verse_id" => verse_id}},
            %{
              assigns: %{
                kv_verses: verses,
                marks: [%Mark{state: :draft, verse_id: curr_verse_id} = d_mark | marks]
              }
            } = socket
          )
          when is_binary(curr_verse_id) and verse_id != curr_verse_id do
        # binding here blocks the stream from appending to quote
        bind = Draft.bind_node(bind)

        bound_verses =
          verses
           |> then(&put_in(&1[verse_id].binding, bind))
           |> then(&put_in(&1[curr_verse_id].binding, nil))

    +    updated_draft_mark = d_mark |> Mark.update_mark(%{binding: bind, verse_id: verse_id})
    +
         {:noreply,
          socket
          |> mutate_verses(curr_verse_id, bound_verses)
          |> mutate_verses(verse_id, bound_verses)
    -     |> assign(:marks, [%{d_mark | binding: bind, verse_id: verse_id} | marks])}
    +     |> assign(:marks, [updated_draft_mark | marks])}
       end
    ```

3.  add ui state structs: all of the relevant ui states have structs
    that are intended to be static interfaces. this felt better than
    directly keeping state within various sockets and is done with a
    view to remove live components and change them to function
    components wherever possible.

4.  bugfix for `order()`:

    - it had an off-by-one-error
    - shifted it to Vyasa.Sangh.Mark
    - also note that the order shall be 1-indexed instead of 0-indexed
      for human-friendliness

5.  minor fixes:

    1.  fix update<sub>mark</sub> default argument

        ``` diff
        -def update_mark(%Mark{} = draft_mark, opts \\ []) do
        +def update_mark(%Mark{} = draft_mark, opts \\ %{}) do
        ```

1.  In this commit, the marks<sub>ui</sub> is NOT kept by the read
    context module, that's why when I update things by create mark or
    delete mark, the ui state is not preserved and initial, default
    state is seen. This was intentionally done in this commit because
    I'm having problems with duplicate ids for verses for some reason,
    I'll show it in the next commit, so that the problem can be clearly
    seen.

* [BUGGY] keep marks_ui within ReadContext

This is buggy, not sure why there's a duplicate yet.  will come back to
it after lunch

Replication Steps:
1. delete all marks and see there's no error
2. create first mark ==> no error
3. create second mark ==> crashes due to duplicate verse id

Crash dump:

[debug] Replied in 13ms
[error] GenServer #PID<0.8416.0> terminating
** (RuntimeError) found duplicate ID "verse-7d9d588a-34fc-4f19-b974-fc32b49b6a61" for component VyasaWeb.Context.Read.VerseMatrix when rendering template
    (phoenix_live_view 1.0.0-rc.6) lib/phoenix_live_view/diff.ex:634: anonymous fn/5 in Phoenix.LiveView.Diff.render_pending_components/6
    (elixir 1.17.2) lib/enum.ex:2531: Enum."-reduce/3-lists^foldl/2-0-"/3
    (phoenix_live_view 1.0.0-rc.6) lib/phoenix_live_view/diff.ex:631: anonymous fn/4 in Phoenix.LiveView.Diff.render_pending_components/6
    (stdlib 5.2.3) maps.erl:416: :maps.fold_1/4
    (phoenix_live_view 1.0.0-rc.6) lib/phoenix_live_view/diff.ex:625: Phoenix.LiveView.Diff.render_pending_components/6
    (phoenix_live_view 1.0.0-rc.6) lib/phoenix_live_view/diff.ex:217: Phoenix.LiveView.Diff.write_component/4
    (phoenix_live_view 1.0.0-rc.6) lib/phoenix_live_view/channel.ex:662: Phoenix.LiveView.Channel.component_handle/4
    (stdlib 5.2.3) gen_server.erl:1095: :gen_server.try_handle_info/3
    (stdlib 5.2.3) gen_server.erl:1183: :gen_server.handle_msg/6
    (stdlib 5.2.3) proc_lib.erl:251: :proc_lib.wake_up/3
Last message: %Phoenix.Socket.Message{topic: "lv:phx-F_1MH_6F0ciqVqwi", event: "event", payload: %{"cid" => 3, "event" => "createMark", "type" => "form", "value" => "body=how+about+now%2C+any+duplicate%3F"}, ref: "23", join_ref: "4"}
State: %{socket: #Phoenix.LiveView.Socket<id: "phx-F_1MH_6F0ciqVqwi", endpoint: VyasaWeb.Endpoint, view: VyasaWeb.ModeLive.Mediator, parent_pid: nil, root_pid: #PID<0.8416.0>, router: VyasaWeb.Router, assigns: %{mode: %VyasaWeb.ModeLive.UserMode{mode: "read", default_ui_state: %VyasaWeb.ModeLive.UiState{show_media_bridge?: true, show_action_bar?: true}, mode_icon_name: "hero-book-open", quick_actions: [:mark_quote, :bookmark], control_panel_modes: ["discuss"], mode_actions: [:mark_quote, :bookmark], action_bar_actions: [:nav_back, :nav_fwd], action_bar_info_types: nil, action_bar_component: VyasaWeb.MediaLive.MediaBridge, action_bar_component_selector: "media-bridge", control_panel_component: VyasaWeb.ControlPanel, control_panel_component_selector: "control-panel", mode_context_component: VyasaWeb.Context.Read, mode_context_component_selector: "read"}, session: %VyasaWeb.Session{name: "ritesh kumar", id: "IhrQV0ypqg8bHakbvb2bymNF", active: true, sangh: %Vyasa.Sangh.Session{__meta__: #Ecto.Schema.Metadata<:loaded, "sessions">, id: "164eb05d-221a-4939-b180-8394e1a5515f", sheafs: #Ecto.Association.NotLoaded<association :sheafs is not loaded>, inserted_at: ~U[2024-09-27 00:51:48Z], updated_at: ~U[2024-09-27 00:51:48Z]}, last_opened: "2024-09-23T11:03:32.022987Z"}, __changed__: %{}, flash: %{}, locale: "en-GB", url_params: %{"chap_no" => "1", "source_title" => "hanuman_chalisa"}, live_action: :show_verses, ui_state: %VyasaWeb.ModeLive.UiState{show_media_bridge?: true, show_action_bar?: true}, device_type: :desktop, tz: %{timezone: "Asia/Singapore", timezone_offset: 480}}, transport_pid: #PID<0.8403.0>, ...>, components: {%{15 => {VyasaWeb.Context.Read.VerseMatrix, "verse-aa3ad88b-0de1-443e-b471-c08a44e67c61", %{id: "verse-aa3ad88b-0de1-443e-b471-c08a44e67c61", edge: [%{title: "1.10", field: [:body], verseup: {:big, "dn"}}, %{node: %Vyasa.Written.Translation{__meta__: #Ecto.Schema.Metadata<:loaded, "translations">, id: "651676b6-ffc3-41c1-b525-f376989f639e", lang: "en", type: "verses", target: %Vyasa.Written.Translation.Target{id: "dd20a94f-8f34-49f8-8da8-4321cfecf172", title: nil, title_translit: nil, body: "प्रभु चरित्र सुनिबे को रसिया ।\n\nराम लखन सीता मन बसिया ॥८॥", body_meant: nil, body_translit: "prabhu caritra sunibe ko rasiyā .\n\nrāma lakhana sītā mana basiyā ..8..", body_translit_meant: "You feel extremely delighted in listening to Lord Rama’s doings and conduct. Lord Rama, Mother Sita, and Lord Laxmana dwell forever in your heart."}, verse_id: "aa3ad88b-0de1-443e-b471-c08a44e67c61", verse: #Ecto.Association.NotLoaded<association :verse is not loaded>, chapter_no: nil, chapter: #Ecto.Association.NotLoaded<association :chapter is not loaded>, source_id: "63918acd-77a9-451a-b8d1-8d5b73208eae", source: #Ecto.Association.NotLoaded<association :source is not loaded>}, field: [:target, :body_translit], verseup: :mid}, %{node: %Vyasa.Written.Translation{__meta__: #Ecto.Schema.Metadata<:loaded, "translations">, id: "651676b6-ffc3-41c1-b525-f376989f639e", lang: "en", type: "verses", target: %Vyasa.Written.Translation.Target{id: "dd20a94f-8f34-49f8-8da8-4321cfecf172", title: nil, title_translit: nil, body: "प्रभु चरित्र सुनिबे को रसिया ।\n\nराम लखन सीता मन बसिया ॥८॥", body_meant: nil, body_translit: "prabhu caritra sunibe ko rasiyā .\n\nrāma lakhana sītā mana basiyā ..8..", body_translit_meant: "You feel extremely delighted in listening to Lord Rama’s doings and conduct. Lord Rama, Mother Sita, and Lord Laxmana dwell forever in your heart."}, verse_id: "aa3ad88b-0de1-443e-b471-c08a44e67c61", verse: #Ecto.Association.NotLoaded<association :verse is not loaded>, chapter_no: nil, chapter: #Ecto.Association.NotLoaded<association :chapter is not loaded>, source_id: "63918acd-77a9-451a-b8d1-8d5b73208eae", source: #Ecto.Association.NotLoaded<association :source is not loaded>}, field: [:target, :body_translit_meant], verseup: :mid}, %{node: %Vyasa.Written.Translation{__meta__: #Ecto.Schema.Metadata<:loaded, "translations">, id: "651676b6-ffc3-41c1-b525-f376989f639e", lang: "en", type: "verses", target: %Vyasa.Written.Translation.Target{id: "dd20a94f-8f34-49f8-8da8-4321cfecf172", title: nil, title_translit: nil, body: "प्रभु चरित्र सुनिबे को रसिया ।\n\nराम लखन सीता मन बसिया ॥८॥", body_meant: nil, body_translit: "prabhu caritra sunibe ko rasiyā .\n\nrāma lakhana sītā mana basiyā ..8..", body_translit_meant: "You feel extremely delighted in listening to Lord Rama’s doings and conduct. Lord Rama, Mother Sita, and Lord Laxmana dwell forever in your heart."}, verse_id: "aa3ad88b-0de1-443e-b471-c08a44e67c61", verse: #Ecto.Association.NotLoaded<association :verse is not loaded>, chapter_no: nil, chapter: #Ecto.Association.NotLoaded<association :chapter is not loaded>, source_id: "63918acd-77a9-451a-b8d1-8d5b73208eae", source: #Ecto.Association.NotLoaded<association :source is not loaded>}, field: [:target, :body], verseup: :mid}], __changed__: %{}, flash: %{}, marks: [%Vyasa.Sangh.Mark{__meta__: #Ecto.Schema.Metadata<:loaded, "marks">, id: "5dfdb167-6c57-46dd-a0c4-10b52cb03a85", body: "wonderful", order: 2, state: :live, verse_id: nil, sheaf_id: "7f4ab16b-0caf-4009-ba2a-3ddded81d9aa", sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>, binding_id: "001da594-3808-46cf-9b9c-5dfb3559780e", binding: %Vyasa.Adapters.Binding{__meta__: #Ecto.Schema.Metadata<:loaded, "bindings">, id: "001da594-3808-46cf-9b9c-5dfb3559780e", w_type: nil, field_key: ["target", "body_translit_meant"], node_id: nil, verse_id: nil, verse: #Ecto.Association.NotLoaded<association :verse is not loaded>, chapter_no: nil, chapter: #Ecto.Association.NotLoaded<association :chapter is not loaded>, source_id: nil, source: #Ecto.Association.NotLoaded<association :source is not loaded>, translation_id: "97a7a662-a91b-486f-93e8-7ae932d01a1a", translation: #Ecto.Association.NotLoaded<association :translation is not loaded>, sheaf_id: nil, sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>, window: nil}, inserted_at: ~U[2024-10-11 04:31:50Z], updated_at: ~U[2024-10-11 04:31:50Z]}, %Vyasa.Sangh.Mark{__meta__: #Ecto.Schema.Metadata<:loaded, "marks">, id: "273a093d-4f90-40a4-b19a-2f8f7825d201", body: "truncated utc datetime", order: 1, state: :live, verse_id: nil, sheaf_id: "7f4ab16b-0caf-4009-ba2a-3ddded81d9aa", sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>, binding_id: "ef39315b-530c-4841-ba32-86773f451727", binding: %Vyasa.Adapt (truncated)
[debug] MOUNT VyasaWeb.ModeLive.Mediator
  Parameters: %{"chap_no" => "1", "source_title" => "hanuman_chalisa"}
  Session: %{"_csrf_token" => "DJ-RIoXwEzHW82rbb21le_8k"}
[debug] QUERY OK source="sessions" db=3.5ms idle=1690.4ms
SELECT s0."id", s0."inserted_at", s0."updated_at" FROM "sessions" AS s0 WHERE (s0."id" = $1) ["164eb05d-221a-4939-b180-8394e1a5515f"]
↳

* Fix duplicate id issue on verse matrix

* Standardise use of @event_target, cleanups

When using @event_target, the intent is that phx-target values
will be passed around. This must be agnostic to the 2 main ways of
supplying that argument, as a HTML selector, or as a module name (or @Myself).
Therefore, we should discourage ourselves from doing format-strings at
the point of the @event_target being supplied as an argument, meaning:

good, because agnostic:
phx-target={@event_target}

bad, because hardcoded:
phx-target={"#" <> @event_target}
* in this case, the event trigger will throw a dom error.

* [Attempt]: Sanitise, defrag orders in marks-list

If this is an anti-pattern, then this commit should be reverted.

* UI fixes: hide buttons on marks when !is_editable?

* Add in stub event handlers to prevent crashes

Temporary stuff, will be addressed in immediate-next PR

* Minor changes

* trigger_dom_refresh()->cascade_stream_change()

---------

Co-authored-by: ks0m1c_dharma <[email protected]>

socket
|> apply_action(:show_verses, params |> Map.put("chap_no", chapter.no))
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ks0m1c

would encourage the use of commit message to signpost the bugfix

e.g. in the message body:
"this fixes the issue on navigation that existed in the previous use of helm, when we are short-circuiting the nav for sources with a single chapter."

ks0m1c_dharma and others added 3 commits October 18, 2024 09:53
This fixes the error where our previous way of doing a re-direct wasn't
working.
The requirement is that for sources without multiple chapters, the sole
chapter should be loaded directly.

There are 2 ways to go about doing this:

A) do a redirect (push-patch) on this scenario

B) since it's all handled by the apply_actions within the read context,
pipe the execution into the apply action of :show_verses.

This commit favours B over A. It's unclear why A doesn't work.
* Add generic debug dump component

This makes life easy when wiring things up

* Rename namespace for Context.Read.*

* Groundwork: add discuss component w sheafs

* Init Context.Components mod for common components

* Add skeletons for Sheaf Container

Container managers sheaf state within itself.
Should actually make the verse-matrix use this container, sometime.

* Minor changes, add some TODOs to share

explicit todos

Minor change

* Add live component EditableMarkDisplay

* Add UI improvements to EditableMarkDisplay

The edit button on quick draft should only be seen when the dropdown is
expanded and all the marks can be seen. The general pattern I'm trying
to follow is that buttons should only be shown when an action makes
sense. So here, if the user can't even see the marks currently
accumulating, then the user shouldn't have the chance to edit any marks.

Notice that the EditableMarkDisplay is a live_component that is a child
of a function component (collapsible_marks_display). This is so that it can keep its own state and
do it's own event-handling. I'm not sure if this is pattern-breaking.
A reference to the actual parent live_component that calls collapsible_marks_display
will always be there in case there's a need for the parent to handle
any particular events. So comms b/w live_components is still going to be
via phx-target values.

* Change <input/> -> <textarea/> fr quick_draft_form

* Add tailwind config for custom svg icons

not sure how the scaling for this works, seems like i can't just put in
the class="h-5 w-5" to do the scaling

* Let custom svg be scalable

* Subtly shift the ping indicator to control panel

* Marks ordering in Sheaf and L-Trees  (#114)

* do sheafs grow on trees

* sangh session dealing with lineage

* Solve initial order problem

* fix: ensure non-null id used @ EditableMarkDisplay

---------

Co-authored-by: ks0m1c_dharma <[email protected]>

* Trigger Diff

* TOMBSTONING

* Fix bugs and revert ui for read_mode:delete marks

1.  JIT generate id for marks yet to be inserted to the db: instead of
    using a temp id, I'm actually assigning a JIT-generated id for a
    mark even if that isn't inserted into the db yet. this has two
    benefits: div ids have meaningful static ids (e.g.
    mark-container-\<\> mark.id) regardless of whether that mark has
    been inserted into the db or not. While doing this, the changeset
    for marks has been udpated to add id as well. This fixes a bunch of
    id-based errors as well.

2.  while doing 1, it came to light that the bindHoverune handlers were
    not handling the draft mark update properly (i.e. not using the
    already existing update function in mark) . it's changed now,
    example of the diff:

    ``` diff
      @impl true
      def handle_event(
            "bindHoveRune",
            %{"binding" => bind = %{"verse_id" => verse_id}},
            %{
              assigns: %{
                kv_verses: verses,
                marks: [%Mark{state: :draft, verse_id: curr_verse_id} = d_mark | marks]
              }
            } = socket
          )
          when is_binary(curr_verse_id) and verse_id != curr_verse_id do
        # binding here blocks the stream from appending to quote
        bind = Draft.bind_node(bind)

        bound_verses =
          verses
           |> then(&put_in(&1[verse_id].binding, bind))
           |> then(&put_in(&1[curr_verse_id].binding, nil))

    +    updated_draft_mark = d_mark |> Mark.update_mark(%{binding: bind, verse_id: verse_id})
    +
         {:noreply,
          socket
          |> mutate_verses(curr_verse_id, bound_verses)
          |> mutate_verses(verse_id, bound_verses)
    -     |> assign(:marks, [%{d_mark | binding: bind, verse_id: verse_id} | marks])}
    +     |> assign(:marks, [updated_draft_mark | marks])}
       end
    ```

3.  add ui state structs: all of the relevant ui states have structs
    that are intended to be static interfaces. this felt better than
    directly keeping state within various sockets and is done with a
    view to remove live components and change them to function
    components wherever possible.

4.  bugfix for `order()`:

    - it had an off-by-one-error
    - shifted it to Vyasa.Sangh.Mark
    - also note that the order shall be 1-indexed instead of 0-indexed
      for human-friendliness

5.  minor fixes:

    1.  fix update<sub>mark</sub> default argument

        ``` diff
        -def update_mark(%Mark{} = draft_mark, opts \\ []) do
        +def update_mark(%Mark{} = draft_mark, opts \\ %{}) do
        ```

1.  In this commit, the marks<sub>ui</sub> is NOT kept by the read
    context module, that's why when I update things by create mark or
    delete mark, the ui state is not preserved and initial, default
    state is seen. This was intentionally done in this commit because
    I'm having problems with duplicate ids for verses for some reason,
    I'll show it in the next commit, so that the problem can be clearly
    seen.

* [BUGGY] keep marks_ui within ReadContext

This is buggy, not sure why there's a duplicate yet.  will come back to
it after lunch

Replication Steps:
1. delete all marks and see there's no error
2. create first mark ==> no error
3. create second mark ==> crashes due to duplicate verse id

Crash dump:

[debug] Replied in 13ms
[error] GenServer #PID<0.8416.0> terminating
** (RuntimeError) found duplicate ID "verse-7d9d588a-34fc-4f19-b974-fc32b49b6a61" for component VyasaWeb.Context.Read.VerseMatrix when rendering template
    (phoenix_live_view 1.0.0-rc.6) lib/phoenix_live_view/diff.ex:634: anonymous fn/5 in Phoenix.LiveView.Diff.render_pending_components/6
    (elixir 1.17.2) lib/enum.ex:2531: Enum."-reduce/3-lists^foldl/2-0-"/3
    (phoenix_live_view 1.0.0-rc.6) lib/phoenix_live_view/diff.ex:631: anonymous fn/4 in Phoenix.LiveView.Diff.render_pending_components/6
    (stdlib 5.2.3) maps.erl:416: :maps.fold_1/4
    (phoenix_live_view 1.0.0-rc.6) lib/phoenix_live_view/diff.ex:625: Phoenix.LiveView.Diff.render_pending_components/6
    (phoenix_live_view 1.0.0-rc.6) lib/phoenix_live_view/diff.ex:217: Phoenix.LiveView.Diff.write_component/4
    (phoenix_live_view 1.0.0-rc.6) lib/phoenix_live_view/channel.ex:662: Phoenix.LiveView.Channel.component_handle/4
    (stdlib 5.2.3) gen_server.erl:1095: :gen_server.try_handle_info/3
    (stdlib 5.2.3) gen_server.erl:1183: :gen_server.handle_msg/6
    (stdlib 5.2.3) proc_lib.erl:251: :proc_lib.wake_up/3
Last message: %Phoenix.Socket.Message{topic: "lv:phx-F_1MH_6F0ciqVqwi", event: "event", payload: %{"cid" => 3, "event" => "createMark", "type" => "form", "value" => "body=how+about+now%2C+any+duplicate%3F"}, ref: "23", join_ref: "4"}
State: %{socket: #Phoenix.LiveView.Socket<id: "phx-F_1MH_6F0ciqVqwi", endpoint: VyasaWeb.Endpoint, view: VyasaWeb.ModeLive.Mediator, parent_pid: nil, root_pid: #PID<0.8416.0>, router: VyasaWeb.Router, assigns: %{mode: %VyasaWeb.ModeLive.UserMode{mode: "read", default_ui_state: %VyasaWeb.ModeLive.UiState{show_media_bridge?: true, show_action_bar?: true}, mode_icon_name: "hero-book-open", quick_actions: [:mark_quote, :bookmark], control_panel_modes: ["discuss"], mode_actions: [:mark_quote, :bookmark], action_bar_actions: [:nav_back, :nav_fwd], action_bar_info_types: nil, action_bar_component: VyasaWeb.MediaLive.MediaBridge, action_bar_component_selector: "media-bridge", control_panel_component: VyasaWeb.ControlPanel, control_panel_component_selector: "control-panel", mode_context_component: VyasaWeb.Context.Read, mode_context_component_selector: "read"}, session: %VyasaWeb.Session{name: "ritesh kumar", id: "IhrQV0ypqg8bHakbvb2bymNF", active: true, sangh: %Vyasa.Sangh.Session{__meta__: #Ecto.Schema.Metadata<:loaded, "sessions">, id: "164eb05d-221a-4939-b180-8394e1a5515f", sheafs: #Ecto.Association.NotLoaded<association :sheafs is not loaded>, inserted_at: ~U[2024-09-27 00:51:48Z], updated_at: ~U[2024-09-27 00:51:48Z]}, last_opened: "2024-09-23T11:03:32.022987Z"}, __changed__: %{}, flash: %{}, locale: "en-GB", url_params: %{"chap_no" => "1", "source_title" => "hanuman_chalisa"}, live_action: :show_verses, ui_state: %VyasaWeb.ModeLive.UiState{show_media_bridge?: true, show_action_bar?: true}, device_type: :desktop, tz: %{timezone: "Asia/Singapore", timezone_offset: 480}}, transport_pid: #PID<0.8403.0>, ...>, components: {%{15 => {VyasaWeb.Context.Read.VerseMatrix, "verse-aa3ad88b-0de1-443e-b471-c08a44e67c61", %{id: "verse-aa3ad88b-0de1-443e-b471-c08a44e67c61", edge: [%{title: "1.10", field: [:body], verseup: {:big, "dn"}}, %{node: %Vyasa.Written.Translation{__meta__: #Ecto.Schema.Metadata<:loaded, "translations">, id: "651676b6-ffc3-41c1-b525-f376989f639e", lang: "en", type: "verses", target: %Vyasa.Written.Translation.Target{id: "dd20a94f-8f34-49f8-8da8-4321cfecf172", title: nil, title_translit: nil, body: "प्रभु चरित्र सुनिबे को रसिया ।\n\nराम लखन सीता मन बसिया ॥८॥", body_meant: nil, body_translit: "prabhu caritra sunibe ko rasiyā .\n\nrāma lakhana sītā mana basiyā ..8..", body_translit_meant: "You feel extremely delighted in listening to Lord Rama’s doings and conduct. Lord Rama, Mother Sita, and Lord Laxmana dwell forever in your heart."}, verse_id: "aa3ad88b-0de1-443e-b471-c08a44e67c61", verse: #Ecto.Association.NotLoaded<association :verse is not loaded>, chapter_no: nil, chapter: #Ecto.Association.NotLoaded<association :chapter is not loaded>, source_id: "63918acd-77a9-451a-b8d1-8d5b73208eae", source: #Ecto.Association.NotLoaded<association :source is not loaded>}, field: [:target, :body_translit], verseup: :mid}, %{node: %Vyasa.Written.Translation{__meta__: #Ecto.Schema.Metadata<:loaded, "translations">, id: "651676b6-ffc3-41c1-b525-f376989f639e", lang: "en", type: "verses", target: %Vyasa.Written.Translation.Target{id: "dd20a94f-8f34-49f8-8da8-4321cfecf172", title: nil, title_translit: nil, body: "प्रभु चरित्र सुनिबे को रसिया ।\n\nराम लखन सीता मन बसिया ॥८॥", body_meant: nil, body_translit: "prabhu caritra sunibe ko rasiyā .\n\nrāma lakhana sītā mana basiyā ..8..", body_translit_meant: "You feel extremely delighted in listening to Lord Rama’s doings and conduct. Lord Rama, Mother Sita, and Lord Laxmana dwell forever in your heart."}, verse_id: "aa3ad88b-0de1-443e-b471-c08a44e67c61", verse: #Ecto.Association.NotLoaded<association :verse is not loaded>, chapter_no: nil, chapter: #Ecto.Association.NotLoaded<association :chapter is not loaded>, source_id: "63918acd-77a9-451a-b8d1-8d5b73208eae", source: #Ecto.Association.NotLoaded<association :source is not loaded>}, field: [:target, :body_translit_meant], verseup: :mid}, %{node: %Vyasa.Written.Translation{__meta__: #Ecto.Schema.Metadata<:loaded, "translations">, id: "651676b6-ffc3-41c1-b525-f376989f639e", lang: "en", type: "verses", target: %Vyasa.Written.Translation.Target{id: "dd20a94f-8f34-49f8-8da8-4321cfecf172", title: nil, title_translit: nil, body: "प्रभु चरित्र सुनिबे को रसिया ।\n\nराम लखन सीता मन बसिया ॥८॥", body_meant: nil, body_translit: "prabhu caritra sunibe ko rasiyā .\n\nrāma lakhana sītā mana basiyā ..8..", body_translit_meant: "You feel extremely delighted in listening to Lord Rama’s doings and conduct. Lord Rama, Mother Sita, and Lord Laxmana dwell forever in your heart."}, verse_id: "aa3ad88b-0de1-443e-b471-c08a44e67c61", verse: #Ecto.Association.NotLoaded<association :verse is not loaded>, chapter_no: nil, chapter: #Ecto.Association.NotLoaded<association :chapter is not loaded>, source_id: "63918acd-77a9-451a-b8d1-8d5b73208eae", source: #Ecto.Association.NotLoaded<association :source is not loaded>}, field: [:target, :body], verseup: :mid}], __changed__: %{}, flash: %{}, marks: [%Vyasa.Sangh.Mark{__meta__: #Ecto.Schema.Metadata<:loaded, "marks">, id: "5dfdb167-6c57-46dd-a0c4-10b52cb03a85", body: "wonderful", order: 2, state: :live, verse_id: nil, sheaf_id: "7f4ab16b-0caf-4009-ba2a-3ddded81d9aa", sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>, binding_id: "001da594-3808-46cf-9b9c-5dfb3559780e", binding: %Vyasa.Adapters.Binding{__meta__: #Ecto.Schema.Metadata<:loaded, "bindings">, id: "001da594-3808-46cf-9b9c-5dfb3559780e", w_type: nil, field_key: ["target", "body_translit_meant"], node_id: nil, verse_id: nil, verse: #Ecto.Association.NotLoaded<association :verse is not loaded>, chapter_no: nil, chapter: #Ecto.Association.NotLoaded<association :chapter is not loaded>, source_id: nil, source: #Ecto.Association.NotLoaded<association :source is not loaded>, translation_id: "97a7a662-a91b-486f-93e8-7ae932d01a1a", translation: #Ecto.Association.NotLoaded<association :translation is not loaded>, sheaf_id: nil, sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>, window: nil}, inserted_at: ~U[2024-10-11 04:31:50Z], updated_at: ~U[2024-10-11 04:31:50Z]}, %Vyasa.Sangh.Mark{__meta__: #Ecto.Schema.Metadata<:loaded, "marks">, id: "273a093d-4f90-40a4-b19a-2f8f7825d201", body: "truncated utc datetime", order: 1, state: :live, verse_id: nil, sheaf_id: "7f4ab16b-0caf-4009-ba2a-3ddded81d9aa", sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>, binding_id: "ef39315b-530c-4841-ba32-86773f451727", binding: %Vyasa.Adapt (truncated)
[debug] MOUNT VyasaWeb.ModeLive.Mediator
  Parameters: %{"chap_no" => "1", "source_title" => "hanuman_chalisa"}
  Session: %{"_csrf_token" => "DJ-RIoXwEzHW82rbb21le_8k"}
[debug] QUERY OK source="sessions" db=3.5ms idle=1690.4ms
SELECT s0."id", s0."inserted_at", s0."updated_at" FROM "sessions" AS s0 WHERE (s0."id" = $1) ["164eb05d-221a-4939-b180-8394e1a5515f"]
↳

* Fix duplicate id issue on verse matrix

* Standardise use of @event_target, cleanups

When using @event_target, the intent is that phx-target values
will be passed around. This must be agnostic to the 2 main ways of
supplying that argument, as a HTML selector, or as a module name (or @Myself).
Therefore, we should discourage ourselves from doing format-strings at
the point of the @event_target being supplied as an argument, meaning:

good, because agnostic:
phx-target={@event_target}

bad, because hardcoded:
phx-target={"#" <> @event_target}
* in this case, the event trigger will throw a dom error.

* [Attempt]: Sanitise, defrag orders in marks-list

If this is an anti-pattern, then this commit should be reverted.

* UI fixes: hide buttons on marks when !is_editable?

* Add in stub event handlers to prevent crashes

Temporary stuff, will be addressed in immediate-next PR

* Minor changes

* Toggle edit state for marks content

* Partial implementation of edit marks

the form stuff doesn't exist so it's not wired up yet. To be frank,
im' not sure how to set up a form without it needing to hold state.

* [BUGGY] Wire up form update for edit

this does the following:
1. wires up the form like how we usedd it in createMark
2. actually captures the event properly within the event handler,
everything looks good at that point, even the edit_mark_in_marks
function on inspection looks good
3. the marks is getting assigned to properly because the newly edited
mark content is seen after doing a dom refresh
4. HOWEVER, the print statement at the sheaf_update function DOES NOT
show the correct, updated marks in the sheaf

here's a dump for it for reference

[debug] HANDLE EVENT "editMarkContent" in VyasaWeb.ModeLive.Mediator
  Component: VyasaWeb.Context.Read
  Parameters: %{"mark_id" => "02218551-591f-4450-abbd-a7b7d76fd48e"}
[debug] Replied in 2ms
[debug] HANDLE EVENT "editMarkContent" in VyasaWeb.ModeLive.Mediator
  Component: VyasaWeb.Context.Read
  Parameters: %{"mark_body" => "  testing\n\n\nwhat hte heck", "mark_id" => "02218551-591f-4450-abbd-a7b7d76fd48e"}
>>> UPDATE SHEAF -- SHOULD BE WRITING TO DB NOW: %Vyasa.Sangh.Sheaf{
  __meta__: #Ecto.Schema.Metadata<:loaded, "sheafs">,
  id: "7f4ab16b-0caf-4009-ba2a-3ddded81d9aa",
  body: nil,
  active: true,
  path: %EctoLtree.LabelTree{labels: ["7f4ab16b"]},
  signature: nil,
  traits: ["draft"],
  child_count: 0,
  session_id: "164eb05d-221a-4939-b180-8394e1a5515f",
  session: #Ecto.Association.NotLoaded<association :session is not loaded>,
  parent_id: nil,
  parent: #Ecto.Association.NotLoaded<association :parent is not loaded>,
  marks: [
    %Vyasa.Sangh.Mark{
      __meta__: #Ecto.Schema.Metadata<:loaded, "marks">,
      id: "555eb625-e392-496e-9831-4f4c130be6fd",
      body: "wonderful stuff",
      order: 5,
      state: :live,
      verse_id: nil,
      sheaf_id: "7f4ab16b-0caf-4009-ba2a-3ddded81d9aa",
      sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>,
      binding_id: "072124d0-5e27-4601-832f-35eaa6426879",
      binding: %Vyasa.Adapters.Binding{
        __meta__: #Ecto.Schema.Metadata<:loaded, "bindings">,
        id: "072124d0-5e27-4601-832f-35eaa6426879",
        w_type: nil,
        field_key: ["target", "body_translit_meant"],
        node_id: nil,
        verse_id: nil,
        verse: #Ecto.Association.NotLoaded<association :verse is not loaded>,
        chapter_no: nil,
        chapter: #Ecto.Association.NotLoaded<association :chapter is not loaded>,
        source_id: nil,
        source: #Ecto.Association.NotLoaded<association :source is not loaded>,
        translation_id: "97a7a662-a91b-486f-93e8-7ae932d01a1a",
        translation: #Ecto.Association.NotLoaded<association :translation is not loaded>,
        sheaf_id: nil,
        sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>,
        window: nil
      },
      inserted_at: ~U[2024-10-12 08:46:54Z],
      updated_at: ~U[2024-10-12 08:46:54Z]
    },
    %Vyasa.Sangh.Mark{
      __meta__: #Ecto.Schema.Metadata<:loaded, "marks">,
      id: "b22a5661-8268-4875-be26-a12256414136",
      body: nil,
      order: 5,
      state: :draft,
      verse_id: nil,
      sheaf_id: "7f4ab16b-0caf-4009-ba2a-3ddded81d9aa",
      sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>,
      binding_id: "90e18044-73b2-4ede-a149-a381de893b9f",
      binding: %Vyasa.Adapters.Binding{
        __meta__: #Ecto.Schema.Metadata<:loaded, "bindings">,
        id: "90e18044-73b2-4ede-a149-a381de893b9f",
        w_type: nil,
        field_key: ["target", "body_translit_meant"],
        node_id: nil,
        verse_id: nil,
        verse: #Ecto.Association.NotLoaded<association :verse is not loaded>,
        chapter_no: nil,
        chapter: #Ecto.Association.NotLoaded<association :chapter is not loaded>,
        source_id: nil,
        source: #Ecto.Association.NotLoaded<association :source is not loaded>,
        translation_id: "fc80709a-39dc-4b9c-95c3-1d64ce818302",
        translation: #Ecto.Association.NotLoaded<association :translation is not loaded>,
        sheaf_id: nil,
        sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>,
        window: nil
      },
      inserted_at: ~U[2024-10-12 09:52:40Z],
      updated_at: ~U[2024-10-12 09:52:40Z]
    },
    %Vyasa.Sangh.Mark{
      __meta__: #Ecto.Schema.Metadata<:loaded, "marks">,
      id: "8af43833-575c-4eb8-83b1-eb4e58509e4c",
      body: nil,
      order: 4,
      state: :draft,
      verse_id: nil,
      sheaf_id: "7f4ab16b-0caf-4009-ba2a-3ddded81d9aa",
      sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>,
      binding_id: "23b70937-ed81-47fe-a560-ee14287bff7d",
      binding: %Vyasa.Adapters.Binding{
        __meta__: #Ecto.Schema.Metadata<:loaded, "bindings">,
        id: "23b70937-ed81-47fe-a560-ee14287bff7d",
        w_type: nil,
        field_key: ["target", "body_translit_meant"],
        node_id: nil,
        verse_id: nil,
        verse: #Ecto.Association.NotLoaded<association :verse is not loaded>,
        chapter_no: nil,
        chapter: #Ecto.Association.NotLoaded<association :chapter is not loaded>,
        source_id: nil,
        source: #Ecto.Association.NotLoaded<association :source is not loaded>,
        translation_id: "97a7a662-a91b-486f-93e8-7ae932d01a1a",
        translation: #Ecto.Association.NotLoaded<association :translation is not loaded>,
        sheaf_id: nil,
        sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>,
        window: nil
      },
      inserted_at: ~U[2024-10-12 09:46:13Z],
      updated_at: ~U[2024-10-12 09:46:13Z]
    },
    %Vyasa.Sangh.Mark{
      __meta__: #Ecto.Schema.Metadata<:loaded, "marks">,
      id: "c7ad47e6-629d-4382-936d-64d757772c4e",
      body: nil,
      order: 3,
      state: :draft,
      verse_id: nil,
      sheaf_id: "7f4ab16b-0caf-4009-ba2a-3ddded81d9aa",
      sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>,
      binding_id: "d5758230-7966-4f9b-8c16-ae13998cd71b",
      binding: %Vyasa.Adapters.Binding{
        __meta__: #Ecto.Schema.Metadata<:loaded, "bindings">,
        id: "d5758230-7966-4f9b-8c16-ae13998cd71b",
        w_type: nil,
        field_key: ["target", "body_translit_meant"],
        node_id: nil,
        verse_id: nil,
        verse: #Ecto.Association.NotLoaded<association :verse is not loaded>,
        chapter_no: nil,
        chapter: #Ecto.Association.NotLoaded<association :chapter is not loaded>,
        source_id: nil,
        source: #Ecto.Association.NotLoaded<association :source is not loaded>,
        translation_id: "fc80709a-39dc-4b9c-95c3-1d64ce818302",
        translation: #Ecto.Association.NotLoaded<association :translation is not loaded>,
        sheaf_id: nil,
        sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>,
        window: nil
      },
      inserted_at: ~U[2024-10-12 09:44:09Z],
      updated_at: ~U[2024-10-12 09:44:09Z]
    },
    %Vyasa.Sangh.Mark{
      __meta__: #Ecto.Schema.Metadata<:loaded, "marks">,
      id: "02218551-591f-4450-abbd-a7b7d76fd48e",
      body: "testing",
      order: 2,
      state: :live,
      verse_id: nil,
      sheaf_id: "7f4ab16b-0caf-4009-ba2a-3ddded81d9aa",
      sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>,
      binding_id: "19ffdc82-a5d8-49c3-8b01-1559736dad80",
      binding: %Vyasa.Adapters.Binding{
        __meta__: #Ecto.Schema.Metadata<:loaded, "bindings">,
        id: "19ffdc82-a5d8-49c3-8b01-1559736dad80",
        w_type: nil,
        field_key: ["target", "body_translit_meant"],
        node_id: nil,
        verse_id: nil,
        verse: #Ecto.Association.NotLoaded<association :verse is not loaded>,
        chapter_no: nil,
        chapter: #Ecto.Association.NotLoaded<association :chapter is not loaded>,
        source_id: nil,
        source: #Ecto.Association.NotLoaded<association :source is not loaded>,
        translation_id: "fc80709a-39dc-4b9c-95c3-1d64ce818302",
        translation: #Ecto.Association.NotLoaded<association :translation is not loaded>,
        sheaf_id: nil,
        sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>,
        window: nil
      },
      inserted_at: ~U[2024-10-12 09:43:19Z],
      updated_at: ~U[2024-10-12 09:43:19Z]
    },
    %Vyasa.Sangh.Mark{
      __meta__: #Ecto.Schema.Metadata<:loaded, "marks">,
      id: "90c6036a-9bd1-4b65-82d5-f121ec4d7867",
      body: nil,
      order: 2,
      state: :draft,
      verse_id: nil,
      sheaf_id: "7f4ab16b-0caf-4009-ba2a-3ddded81d9aa",
      sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>,
      binding_id: "b92f990d-99a2-4f04-a2d4-d1135021ee8c",
      binding: %Vyasa.Adapters.Binding{
        __meta__: #Ecto.Schema.Metadata<:loaded, "bindings">,
        id: "b92f990d-99a2-4f04-a2d4-d1135021ee8c",
        w_type: nil,
        field_key: ["target", "body_translit_meant"],
        node_id: nil,
        verse_id: nil,
        verse: #Ecto.Association.NotLoaded<association :verse is not loaded>,
        chapter_no: nil,
        chapter: #Ecto.Association.NotLoaded<association :chapter is not loaded>,
        source_id: nil,
        source: #Ecto.Association.NotLoaded<association :source is not loaded>,
        translation_id: "97a7a662-a91b-486f-93e8-7ae932d01a1a",
        translation: #Ecto.Association.NotLoaded<association :translation is not loaded>,
        sheaf_id: nil,
        sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>,
        window: nil
      },
      inserted_at: ~U[2024-10-11 09:03:00Z],
      updated_at: ~U[2024-10-11 09:03:00Z]
    }
  ],
  inserted_at: ~N[2024-09-27 00:51:48],
  updated_at: ~N[2024-09-27 00:51:48]
}
[debug] Replied in 81ms
[debug] HANDLE EVENT "verses::focus_toggle_on_quick_mark_drafting" in VyasaWeb.ModeLive.Mediator
  Component: VyasaWeb.Context.Read
  Parameters: %{"is_focusing?" => false, "value" => ""}
[debug] Replied in 129µs
iex([email protected])17>

* marks order force

* old man mark is not feeling so good

* ReWrite how marks get initialised @ :show_verse (#119)

* Minor change in fn signature

* Add init_draft_reflector()

---------

Co-authored-by: ks0m1c_dharma <[email protected]>
* Add generic debug dump component

This makes life easy when wiring things up

* Rename namespace for Context.Read.*

* Groundwork: add discuss component w sheafs

* Init Context.Components mod for common components

* Add skeletons for Sheaf Container

Container managers sheaf state within itself.
Should actually make the verse-matrix use this container, sometime.

* Minor changes, add some TODOs to share

explicit todos

Minor change

* Add live component EditableMarkDisplay

* Add UI improvements to EditableMarkDisplay

The edit button on quick draft should only be seen when the dropdown is
expanded and all the marks can be seen. The general pattern I'm trying
to follow is that buttons should only be shown when an action makes
sense. So here, if the user can't even see the marks currently
accumulating, then the user shouldn't have the chance to edit any marks.

Notice that the EditableMarkDisplay is a live_component that is a child
of a function component (collapsible_marks_display). This is so that it can keep its own state and
do it's own event-handling. I'm not sure if this is pattern-breaking.
A reference to the actual parent live_component that calls collapsible_marks_display
will always be there in case there's a need for the parent to handle
any particular events. So comms b/w live_components is still going to be
via phx-target values.

* Change <input/> -> <textarea/> fr quick_draft_form

* Add tailwind config for custom svg icons

not sure how the scaling for this works, seems like i can't just put in
the class="h-5 w-5" to do the scaling

* Let custom svg be scalable

* Subtly shift the ping indicator to control panel

* Marks ordering in Sheaf and L-Trees  (#114)

* do sheafs grow on trees

* sangh session dealing with lineage

* Solve initial order problem

* fix: ensure non-null id used @ EditableMarkDisplay

---------

Co-authored-by: ks0m1c_dharma <[email protected]>

* Trigger Diff

* TOMBSTONING

* Fix bugs and revert ui for read_mode:delete marks

1.  JIT generate id for marks yet to be inserted to the db: instead of
    using a temp id, I'm actually assigning a JIT-generated id for a
    mark even if that isn't inserted into the db yet. this has two
    benefits: div ids have meaningful static ids (e.g.
    mark-container-\<\> mark.id) regardless of whether that mark has
    been inserted into the db or not. While doing this, the changeset
    for marks has been udpated to add id as well. This fixes a bunch of
    id-based errors as well.

2.  while doing 1, it came to light that the bindHoverune handlers were
    not handling the draft mark update properly (i.e. not using the
    already existing update function in mark) . it's changed now,
    example of the diff:

    ``` diff
      @impl true
      def handle_event(
            "bindHoveRune",
            %{"binding" => bind = %{"verse_id" => verse_id}},
            %{
              assigns: %{
                kv_verses: verses,
                marks: [%Mark{state: :draft, verse_id: curr_verse_id} = d_mark | marks]
              }
            } = socket
          )
          when is_binary(curr_verse_id) and verse_id != curr_verse_id do
        # binding here blocks the stream from appending to quote
        bind = Draft.bind_node(bind)

        bound_verses =
          verses
           |> then(&put_in(&1[verse_id].binding, bind))
           |> then(&put_in(&1[curr_verse_id].binding, nil))

    +    updated_draft_mark = d_mark |> Mark.update_mark(%{binding: bind, verse_id: verse_id})
    +
         {:noreply,
          socket
          |> mutate_verses(curr_verse_id, bound_verses)
          |> mutate_verses(verse_id, bound_verses)
    -     |> assign(:marks, [%{d_mark | binding: bind, verse_id: verse_id} | marks])}
    +     |> assign(:marks, [updated_draft_mark | marks])}
       end
    ```

3.  add ui state structs: all of the relevant ui states have structs
    that are intended to be static interfaces. this felt better than
    directly keeping state within various sockets and is done with a
    view to remove live components and change them to function
    components wherever possible.

4.  bugfix for `order()`:

    - it had an off-by-one-error
    - shifted it to Vyasa.Sangh.Mark
    - also note that the order shall be 1-indexed instead of 0-indexed
      for human-friendliness

5.  minor fixes:

    1.  fix update<sub>mark</sub> default argument

        ``` diff
        -def update_mark(%Mark{} = draft_mark, opts \\ []) do
        +def update_mark(%Mark{} = draft_mark, opts \\ %{}) do
        ```

1.  In this commit, the marks<sub>ui</sub> is NOT kept by the read
    context module, that's why when I update things by create mark or
    delete mark, the ui state is not preserved and initial, default
    state is seen. This was intentionally done in this commit because
    I'm having problems with duplicate ids for verses for some reason,
    I'll show it in the next commit, so that the problem can be clearly
    seen.

* [BUGGY] keep marks_ui within ReadContext

This is buggy, not sure why there's a duplicate yet.  will come back to
it after lunch

Replication Steps:
1. delete all marks and see there's no error
2. create first mark ==> no error
3. create second mark ==> crashes due to duplicate verse id

Crash dump:

[debug] Replied in 13ms
[error] GenServer #PID<0.8416.0> terminating
** (RuntimeError) found duplicate ID "verse-7d9d588a-34fc-4f19-b974-fc32b49b6a61" for component VyasaWeb.Context.Read.VerseMatrix when rendering template
    (phoenix_live_view 1.0.0-rc.6) lib/phoenix_live_view/diff.ex:634: anonymous fn/5 in Phoenix.LiveView.Diff.render_pending_components/6
    (elixir 1.17.2) lib/enum.ex:2531: Enum."-reduce/3-lists^foldl/2-0-"/3
    (phoenix_live_view 1.0.0-rc.6) lib/phoenix_live_view/diff.ex:631: anonymous fn/4 in Phoenix.LiveView.Diff.render_pending_components/6
    (stdlib 5.2.3) maps.erl:416: :maps.fold_1/4
    (phoenix_live_view 1.0.0-rc.6) lib/phoenix_live_view/diff.ex:625: Phoenix.LiveView.Diff.render_pending_components/6
    (phoenix_live_view 1.0.0-rc.6) lib/phoenix_live_view/diff.ex:217: Phoenix.LiveView.Diff.write_component/4
    (phoenix_live_view 1.0.0-rc.6) lib/phoenix_live_view/channel.ex:662: Phoenix.LiveView.Channel.component_handle/4
    (stdlib 5.2.3) gen_server.erl:1095: :gen_server.try_handle_info/3
    (stdlib 5.2.3) gen_server.erl:1183: :gen_server.handle_msg/6
    (stdlib 5.2.3) proc_lib.erl:251: :proc_lib.wake_up/3
Last message: %Phoenix.Socket.Message{topic: "lv:phx-F_1MH_6F0ciqVqwi", event: "event", payload: %{"cid" => 3, "event" => "createMark", "type" => "form", "value" => "body=how+about+now%2C+any+duplicate%3F"}, ref: "23", join_ref: "4"}
State: %{socket: #Phoenix.LiveView.Socket<id: "phx-F_1MH_6F0ciqVqwi", endpoint: VyasaWeb.Endpoint, view: VyasaWeb.ModeLive.Mediator, parent_pid: nil, root_pid: #PID<0.8416.0>, router: VyasaWeb.Router, assigns: %{mode: %VyasaWeb.ModeLive.UserMode{mode: "read", default_ui_state: %VyasaWeb.ModeLive.UiState{show_media_bridge?: true, show_action_bar?: true}, mode_icon_name: "hero-book-open", quick_actions: [:mark_quote, :bookmark], control_panel_modes: ["discuss"], mode_actions: [:mark_quote, :bookmark], action_bar_actions: [:nav_back, :nav_fwd], action_bar_info_types: nil, action_bar_component: VyasaWeb.MediaLive.MediaBridge, action_bar_component_selector: "media-bridge", control_panel_component: VyasaWeb.ControlPanel, control_panel_component_selector: "control-panel", mode_context_component: VyasaWeb.Context.Read, mode_context_component_selector: "read"}, session: %VyasaWeb.Session{name: "ritesh kumar", id: "IhrQV0ypqg8bHakbvb2bymNF", active: true, sangh: %Vyasa.Sangh.Session{__meta__: #Ecto.Schema.Metadata<:loaded, "sessions">, id: "164eb05d-221a-4939-b180-8394e1a5515f", sheafs: #Ecto.Association.NotLoaded<association :sheafs is not loaded>, inserted_at: ~U[2024-09-27 00:51:48Z], updated_at: ~U[2024-09-27 00:51:48Z]}, last_opened: "2024-09-23T11:03:32.022987Z"}, __changed__: %{}, flash: %{}, locale: "en-GB", url_params: %{"chap_no" => "1", "source_title" => "hanuman_chalisa"}, live_action: :show_verses, ui_state: %VyasaWeb.ModeLive.UiState{show_media_bridge?: true, show_action_bar?: true}, device_type: :desktop, tz: %{timezone: "Asia/Singapore", timezone_offset: 480}}, transport_pid: #PID<0.8403.0>, ...>, components: {%{15 => {VyasaWeb.Context.Read.VerseMatrix, "verse-aa3ad88b-0de1-443e-b471-c08a44e67c61", %{id: "verse-aa3ad88b-0de1-443e-b471-c08a44e67c61", edge: [%{title: "1.10", field: [:body], verseup: {:big, "dn"}}, %{node: %Vyasa.Written.Translation{__meta__: #Ecto.Schema.Metadata<:loaded, "translations">, id: "651676b6-ffc3-41c1-b525-f376989f639e", lang: "en", type: "verses", target: %Vyasa.Written.Translation.Target{id: "dd20a94f-8f34-49f8-8da8-4321cfecf172", title: nil, title_translit: nil, body: "प्रभु चरित्र सुनिबे को रसिया ।\n\nराम लखन सीता मन बसिया ॥८॥", body_meant: nil, body_translit: "prabhu caritra sunibe ko rasiyā .\n\nrāma lakhana sītā mana basiyā ..8..", body_translit_meant: "You feel extremely delighted in listening to Lord Rama’s doings and conduct. Lord Rama, Mother Sita, and Lord Laxmana dwell forever in your heart."}, verse_id: "aa3ad88b-0de1-443e-b471-c08a44e67c61", verse: #Ecto.Association.NotLoaded<association :verse is not loaded>, chapter_no: nil, chapter: #Ecto.Association.NotLoaded<association :chapter is not loaded>, source_id: "63918acd-77a9-451a-b8d1-8d5b73208eae", source: #Ecto.Association.NotLoaded<association :source is not loaded>}, field: [:target, :body_translit], verseup: :mid}, %{node: %Vyasa.Written.Translation{__meta__: #Ecto.Schema.Metadata<:loaded, "translations">, id: "651676b6-ffc3-41c1-b525-f376989f639e", lang: "en", type: "verses", target: %Vyasa.Written.Translation.Target{id: "dd20a94f-8f34-49f8-8da8-4321cfecf172", title: nil, title_translit: nil, body: "प्रभु चरित्र सुनिबे को रसिया ।\n\nराम लखन सीता मन बसिया ॥८॥", body_meant: nil, body_translit: "prabhu caritra sunibe ko rasiyā .\n\nrāma lakhana sītā mana basiyā ..8..", body_translit_meant: "You feel extremely delighted in listening to Lord Rama’s doings and conduct. Lord Rama, Mother Sita, and Lord Laxmana dwell forever in your heart."}, verse_id: "aa3ad88b-0de1-443e-b471-c08a44e67c61", verse: #Ecto.Association.NotLoaded<association :verse is not loaded>, chapter_no: nil, chapter: #Ecto.Association.NotLoaded<association :chapter is not loaded>, source_id: "63918acd-77a9-451a-b8d1-8d5b73208eae", source: #Ecto.Association.NotLoaded<association :source is not loaded>}, field: [:target, :body_translit_meant], verseup: :mid}, %{node: %Vyasa.Written.Translation{__meta__: #Ecto.Schema.Metadata<:loaded, "translations">, id: "651676b6-ffc3-41c1-b525-f376989f639e", lang: "en", type: "verses", target: %Vyasa.Written.Translation.Target{id: "dd20a94f-8f34-49f8-8da8-4321cfecf172", title: nil, title_translit: nil, body: "प्रभु चरित्र सुनिबे को रसिया ।\n\nराम लखन सीता मन बसिया ॥८॥", body_meant: nil, body_translit: "prabhu caritra sunibe ko rasiyā .\n\nrāma lakhana sītā mana basiyā ..8..", body_translit_meant: "You feel extremely delighted in listening to Lord Rama’s doings and conduct. Lord Rama, Mother Sita, and Lord Laxmana dwell forever in your heart."}, verse_id: "aa3ad88b-0de1-443e-b471-c08a44e67c61", verse: #Ecto.Association.NotLoaded<association :verse is not loaded>, chapter_no: nil, chapter: #Ecto.Association.NotLoaded<association :chapter is not loaded>, source_id: "63918acd-77a9-451a-b8d1-8d5b73208eae", source: #Ecto.Association.NotLoaded<association :source is not loaded>}, field: [:target, :body], verseup: :mid}], __changed__: %{}, flash: %{}, marks: [%Vyasa.Sangh.Mark{__meta__: #Ecto.Schema.Metadata<:loaded, "marks">, id: "5dfdb167-6c57-46dd-a0c4-10b52cb03a85", body: "wonderful", order: 2, state: :live, verse_id: nil, sheaf_id: "7f4ab16b-0caf-4009-ba2a-3ddded81d9aa", sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>, binding_id: "001da594-3808-46cf-9b9c-5dfb3559780e", binding: %Vyasa.Adapters.Binding{__meta__: #Ecto.Schema.Metadata<:loaded, "bindings">, id: "001da594-3808-46cf-9b9c-5dfb3559780e", w_type: nil, field_key: ["target", "body_translit_meant"], node_id: nil, verse_id: nil, verse: #Ecto.Association.NotLoaded<association :verse is not loaded>, chapter_no: nil, chapter: #Ecto.Association.NotLoaded<association :chapter is not loaded>, source_id: nil, source: #Ecto.Association.NotLoaded<association :source is not loaded>, translation_id: "97a7a662-a91b-486f-93e8-7ae932d01a1a", translation: #Ecto.Association.NotLoaded<association :translation is not loaded>, sheaf_id: nil, sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>, window: nil}, inserted_at: ~U[2024-10-11 04:31:50Z], updated_at: ~U[2024-10-11 04:31:50Z]}, %Vyasa.Sangh.Mark{__meta__: #Ecto.Schema.Metadata<:loaded, "marks">, id: "273a093d-4f90-40a4-b19a-2f8f7825d201", body: "truncated utc datetime", order: 1, state: :live, verse_id: nil, sheaf_id: "7f4ab16b-0caf-4009-ba2a-3ddded81d9aa", sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>, binding_id: "ef39315b-530c-4841-ba32-86773f451727", binding: %Vyasa.Adapt (truncated)
[debug] MOUNT VyasaWeb.ModeLive.Mediator
  Parameters: %{"chap_no" => "1", "source_title" => "hanuman_chalisa"}
  Session: %{"_csrf_token" => "DJ-RIoXwEzHW82rbb21le_8k"}
[debug] QUERY OK source="sessions" db=3.5ms idle=1690.4ms
SELECT s0."id", s0."inserted_at", s0."updated_at" FROM "sessions" AS s0 WHERE (s0."id" = $1) ["164eb05d-221a-4939-b180-8394e1a5515f"]
↳

* Fix duplicate id issue on verse matrix

* Standardise use of @event_target, cleanups

When using @event_target, the intent is that phx-target values
will be passed around. This must be agnostic to the 2 main ways of
supplying that argument, as a HTML selector, or as a module name (or @Myself).
Therefore, we should discourage ourselves from doing format-strings at
the point of the @event_target being supplied as an argument, meaning:

good, because agnostic:
phx-target={@event_target}

bad, because hardcoded:
phx-target={"#" <> @event_target}
* in this case, the event trigger will throw a dom error.

* [Attempt]: Sanitise, defrag orders in marks-list

If this is an anti-pattern, then this commit should be reverted.

* UI fixes: hide buttons on marks when !is_editable?

* Add in stub event handlers to prevent crashes

Temporary stuff, will be addressed in immediate-next PR

* Minor changes

* Toggle edit state for marks content

* Partial implementation of edit marks

the form stuff doesn't exist so it's not wired up yet. To be frank,
im' not sure how to set up a form without it needing to hold state.

* [BUGGY] Wire up form update for edit

this does the following:
1. wires up the form like how we usedd it in createMark
2. actually captures the event properly within the event handler,
everything looks good at that point, even the edit_mark_in_marks
function on inspection looks good
3. the marks is getting assigned to properly because the newly edited
mark content is seen after doing a dom refresh
4. HOWEVER, the print statement at the sheaf_update function DOES NOT
show the correct, updated marks in the sheaf

here's a dump for it for reference

[debug] HANDLE EVENT "editMarkContent" in VyasaWeb.ModeLive.Mediator
  Component: VyasaWeb.Context.Read
  Parameters: %{"mark_id" => "02218551-591f-4450-abbd-a7b7d76fd48e"}
[debug] Replied in 2ms
[debug] HANDLE EVENT "editMarkContent" in VyasaWeb.ModeLive.Mediator
  Component: VyasaWeb.Context.Read
  Parameters: %{"mark_body" => "  testing\n\n\nwhat hte heck", "mark_id" => "02218551-591f-4450-abbd-a7b7d76fd48e"}
>>> UPDATE SHEAF -- SHOULD BE WRITING TO DB NOW: %Vyasa.Sangh.Sheaf{
  __meta__: #Ecto.Schema.Metadata<:loaded, "sheafs">,
  id: "7f4ab16b-0caf-4009-ba2a-3ddded81d9aa",
  body: nil,
  active: true,
  path: %EctoLtree.LabelTree{labels: ["7f4ab16b"]},
  signature: nil,
  traits: ["draft"],
  child_count: 0,
  session_id: "164eb05d-221a-4939-b180-8394e1a5515f",
  session: #Ecto.Association.NotLoaded<association :session is not loaded>,
  parent_id: nil,
  parent: #Ecto.Association.NotLoaded<association :parent is not loaded>,
  marks: [
    %Vyasa.Sangh.Mark{
      __meta__: #Ecto.Schema.Metadata<:loaded, "marks">,
      id: "555eb625-e392-496e-9831-4f4c130be6fd",
      body: "wonderful stuff",
      order: 5,
      state: :live,
      verse_id: nil,
      sheaf_id: "7f4ab16b-0caf-4009-ba2a-3ddded81d9aa",
      sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>,
      binding_id: "072124d0-5e27-4601-832f-35eaa6426879",
      binding: %Vyasa.Adapters.Binding{
        __meta__: #Ecto.Schema.Metadata<:loaded, "bindings">,
        id: "072124d0-5e27-4601-832f-35eaa6426879",
        w_type: nil,
        field_key: ["target", "body_translit_meant"],
        node_id: nil,
        verse_id: nil,
        verse: #Ecto.Association.NotLoaded<association :verse is not loaded>,
        chapter_no: nil,
        chapter: #Ecto.Association.NotLoaded<association :chapter is not loaded>,
        source_id: nil,
        source: #Ecto.Association.NotLoaded<association :source is not loaded>,
        translation_id: "97a7a662-a91b-486f-93e8-7ae932d01a1a",
        translation: #Ecto.Association.NotLoaded<association :translation is not loaded>,
        sheaf_id: nil,
        sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>,
        window: nil
      },
      inserted_at: ~U[2024-10-12 08:46:54Z],
      updated_at: ~U[2024-10-12 08:46:54Z]
    },
    %Vyasa.Sangh.Mark{
      __meta__: #Ecto.Schema.Metadata<:loaded, "marks">,
      id: "b22a5661-8268-4875-be26-a12256414136",
      body: nil,
      order: 5,
      state: :draft,
      verse_id: nil,
      sheaf_id: "7f4ab16b-0caf-4009-ba2a-3ddded81d9aa",
      sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>,
      binding_id: "90e18044-73b2-4ede-a149-a381de893b9f",
      binding: %Vyasa.Adapters.Binding{
        __meta__: #Ecto.Schema.Metadata<:loaded, "bindings">,
        id: "90e18044-73b2-4ede-a149-a381de893b9f",
        w_type: nil,
        field_key: ["target", "body_translit_meant"],
        node_id: nil,
        verse_id: nil,
        verse: #Ecto.Association.NotLoaded<association :verse is not loaded>,
        chapter_no: nil,
        chapter: #Ecto.Association.NotLoaded<association :chapter is not loaded>,
        source_id: nil,
        source: #Ecto.Association.NotLoaded<association :source is not loaded>,
        translation_id: "fc80709a-39dc-4b9c-95c3-1d64ce818302",
        translation: #Ecto.Association.NotLoaded<association :translation is not loaded>,
        sheaf_id: nil,
        sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>,
        window: nil
      },
      inserted_at: ~U[2024-10-12 09:52:40Z],
      updated_at: ~U[2024-10-12 09:52:40Z]
    },
    %Vyasa.Sangh.Mark{
      __meta__: #Ecto.Schema.Metadata<:loaded, "marks">,
      id: "8af43833-575c-4eb8-83b1-eb4e58509e4c",
      body: nil,
      order: 4,
      state: :draft,
      verse_id: nil,
      sheaf_id: "7f4ab16b-0caf-4009-ba2a-3ddded81d9aa",
      sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>,
      binding_id: "23b70937-ed81-47fe-a560-ee14287bff7d",
      binding: %Vyasa.Adapters.Binding{
        __meta__: #Ecto.Schema.Metadata<:loaded, "bindings">,
        id: "23b70937-ed81-47fe-a560-ee14287bff7d",
        w_type: nil,
        field_key: ["target", "body_translit_meant"],
        node_id: nil,
        verse_id: nil,
        verse: #Ecto.Association.NotLoaded<association :verse is not loaded>,
        chapter_no: nil,
        chapter: #Ecto.Association.NotLoaded<association :chapter is not loaded>,
        source_id: nil,
        source: #Ecto.Association.NotLoaded<association :source is not loaded>,
        translation_id: "97a7a662-a91b-486f-93e8-7ae932d01a1a",
        translation: #Ecto.Association.NotLoaded<association :translation is not loaded>,
        sheaf_id: nil,
        sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>,
        window: nil
      },
      inserted_at: ~U[2024-10-12 09:46:13Z],
      updated_at: ~U[2024-10-12 09:46:13Z]
    },
    %Vyasa.Sangh.Mark{
      __meta__: #Ecto.Schema.Metadata<:loaded, "marks">,
      id: "c7ad47e6-629d-4382-936d-64d757772c4e",
      body: nil,
      order: 3,
      state: :draft,
      verse_id: nil,
      sheaf_id: "7f4ab16b-0caf-4009-ba2a-3ddded81d9aa",
      sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>,
      binding_id: "d5758230-7966-4f9b-8c16-ae13998cd71b",
      binding: %Vyasa.Adapters.Binding{
        __meta__: #Ecto.Schema.Metadata<:loaded, "bindings">,
        id: "d5758230-7966-4f9b-8c16-ae13998cd71b",
        w_type: nil,
        field_key: ["target", "body_translit_meant"],
        node_id: nil,
        verse_id: nil,
        verse: #Ecto.Association.NotLoaded<association :verse is not loaded>,
        chapter_no: nil,
        chapter: #Ecto.Association.NotLoaded<association :chapter is not loaded>,
        source_id: nil,
        source: #Ecto.Association.NotLoaded<association :source is not loaded>,
        translation_id: "fc80709a-39dc-4b9c-95c3-1d64ce818302",
        translation: #Ecto.Association.NotLoaded<association :translation is not loaded>,
        sheaf_id: nil,
        sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>,
        window: nil
      },
      inserted_at: ~U[2024-10-12 09:44:09Z],
      updated_at: ~U[2024-10-12 09:44:09Z]
    },
    %Vyasa.Sangh.Mark{
      __meta__: #Ecto.Schema.Metadata<:loaded, "marks">,
      id: "02218551-591f-4450-abbd-a7b7d76fd48e",
      body: "testing",
      order: 2,
      state: :live,
      verse_id: nil,
      sheaf_id: "7f4ab16b-0caf-4009-ba2a-3ddded81d9aa",
      sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>,
      binding_id: "19ffdc82-a5d8-49c3-8b01-1559736dad80",
      binding: %Vyasa.Adapters.Binding{
        __meta__: #Ecto.Schema.Metadata<:loaded, "bindings">,
        id: "19ffdc82-a5d8-49c3-8b01-1559736dad80",
        w_type: nil,
        field_key: ["target", "body_translit_meant"],
        node_id: nil,
        verse_id: nil,
        verse: #Ecto.Association.NotLoaded<association :verse is not loaded>,
        chapter_no: nil,
        chapter: #Ecto.Association.NotLoaded<association :chapter is not loaded>,
        source_id: nil,
        source: #Ecto.Association.NotLoaded<association :source is not loaded>,
        translation_id: "fc80709a-39dc-4b9c-95c3-1d64ce818302",
        translation: #Ecto.Association.NotLoaded<association :translation is not loaded>,
        sheaf_id: nil,
        sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>,
        window: nil
      },
      inserted_at: ~U[2024-10-12 09:43:19Z],
      updated_at: ~U[2024-10-12 09:43:19Z]
    },
    %Vyasa.Sangh.Mark{
      __meta__: #Ecto.Schema.Metadata<:loaded, "marks">,
      id: "90c6036a-9bd1-4b65-82d5-f121ec4d7867",
      body: nil,
      order: 2,
      state: :draft,
      verse_id: nil,
      sheaf_id: "7f4ab16b-0caf-4009-ba2a-3ddded81d9aa",
      sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>,
      binding_id: "b92f990d-99a2-4f04-a2d4-d1135021ee8c",
      binding: %Vyasa.Adapters.Binding{
        __meta__: #Ecto.Schema.Metadata<:loaded, "bindings">,
        id: "b92f990d-99a2-4f04-a2d4-d1135021ee8c",
        w_type: nil,
        field_key: ["target", "body_translit_meant"],
        node_id: nil,
        verse_id: nil,
        verse: #Ecto.Association.NotLoaded<association :verse is not loaded>,
        chapter_no: nil,
        chapter: #Ecto.Association.NotLoaded<association :chapter is not loaded>,
        source_id: nil,
        source: #Ecto.Association.NotLoaded<association :source is not loaded>,
        translation_id: "97a7a662-a91b-486f-93e8-7ae932d01a1a",
        translation: #Ecto.Association.NotLoaded<association :translation is not loaded>,
        sheaf_id: nil,
        sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>,
        window: nil
      },
      inserted_at: ~U[2024-10-11 09:03:00Z],
      updated_at: ~U[2024-10-11 09:03:00Z]
    }
  ],
  inserted_at: ~N[2024-09-27 00:51:48],
  updated_at: ~N[2024-09-27 00:51:48]
}
[debug] Replied in 81ms
[debug] HANDLE EVENT "verses::focus_toggle_on_quick_mark_drafting" in VyasaWeb.ModeLive.Mediator
  Component: VyasaWeb.Context.Read
  Parameters: %{"is_focusing?" => false, "value" => ""}
[debug] Replied in 129µs
iex([email protected])17>

* marks order force

* old man mark is not feeling so good

* ReWrite how marks get initialised @ :show_verse (#119)

* Minor change in fn signature

* Add init_draft_reflector()

* Use custom generic_modal_wrapper

This one has more specific callback attributes and tailwind classes can
be injected to it.

---------

Co-authored-by: ks0m1c_dharma <[email protected]>
rtshkmr and others added 5 commits October 26, 2024 16:47
* Add generic debug dump component

This makes life easy when wiring things up

* Rename namespace for Context.Read.*

* Groundwork: add discuss component w sheafs

* Init Context.Components mod for common components

* Add skeletons for Sheaf Container

Container managers sheaf state within itself.
Should actually make the verse-matrix use this container, sometime.

* Minor changes, add some TODOs to share

explicit todos

Minor change

* Add live component EditableMarkDisplay

* Add UI improvements to EditableMarkDisplay

The edit button on quick draft should only be seen when the dropdown is
expanded and all the marks can be seen. The general pattern I'm trying
to follow is that buttons should only be shown when an action makes
sense. So here, if the user can't even see the marks currently
accumulating, then the user shouldn't have the chance to edit any marks.

Notice that the EditableMarkDisplay is a live_component that is a child
of a function component (collapsible_marks_display). This is so that it can keep its own state and
do it's own event-handling. I'm not sure if this is pattern-breaking.
A reference to the actual parent live_component that calls collapsible_marks_display
will always be there in case there's a need for the parent to handle
any particular events. So comms b/w live_components is still going to be
via phx-target values.

* Change <input/> -> <textarea/> fr quick_draft_form

* Add tailwind config for custom svg icons

not sure how the scaling for this works, seems like i can't just put in
the class="h-5 w-5" to do the scaling

* Let custom svg be scalable

* Subtly shift the ping indicator to control panel

* Marks ordering in Sheaf and L-Trees  (#114)

* do sheafs grow on trees

* sangh session dealing with lineage

* Solve initial order problem

* fix: ensure non-null id used @ EditableMarkDisplay

---------

Co-authored-by: ks0m1c_dharma <[email protected]>

* Trigger Diff

* TOMBSTONING

* Fix bugs and revert ui for read_mode:delete marks

1.  JIT generate id for marks yet to be inserted to the db: instead of
    using a temp id, I'm actually assigning a JIT-generated id for a
    mark even if that isn't inserted into the db yet. this has two
    benefits: div ids have meaningful static ids (e.g.
    mark-container-\<\> mark.id) regardless of whether that mark has
    been inserted into the db or not. While doing this, the changeset
    for marks has been udpated to add id as well. This fixes a bunch of
    id-based errors as well.

2.  while doing 1, it came to light that the bindHoverune handlers were
    not handling the draft mark update properly (i.e. not using the
    already existing update function in mark) . it's changed now,
    example of the diff:

    ``` diff
      @impl true
      def handle_event(
            "bindHoveRune",
            %{"binding" => bind = %{"verse_id" => verse_id}},
            %{
              assigns: %{
                kv_verses: verses,
                marks: [%Mark{state: :draft, verse_id: curr_verse_id} = d_mark | marks]
              }
            } = socket
          )
          when is_binary(curr_verse_id) and verse_id != curr_verse_id do
        # binding here blocks the stream from appending to quote
        bind = Draft.bind_node(bind)

        bound_verses =
          verses
           |> then(&put_in(&1[verse_id].binding, bind))
           |> then(&put_in(&1[curr_verse_id].binding, nil))

    +    updated_draft_mark = d_mark |> Mark.update_mark(%{binding: bind, verse_id: verse_id})
    +
         {:noreply,
          socket
          |> mutate_verses(curr_verse_id, bound_verses)
          |> mutate_verses(verse_id, bound_verses)
    -     |> assign(:marks, [%{d_mark | binding: bind, verse_id: verse_id} | marks])}
    +     |> assign(:marks, [updated_draft_mark | marks])}
       end
    ```

3.  add ui state structs: all of the relevant ui states have structs
    that are intended to be static interfaces. this felt better than
    directly keeping state within various sockets and is done with a
    view to remove live components and change them to function
    components wherever possible.

4.  bugfix for `order()`:

    - it had an off-by-one-error
    - shifted it to Vyasa.Sangh.Mark
    - also note that the order shall be 1-indexed instead of 0-indexed
      for human-friendliness

5.  minor fixes:

    1.  fix update<sub>mark</sub> default argument

        ``` diff
        -def update_mark(%Mark{} = draft_mark, opts \\ []) do
        +def update_mark(%Mark{} = draft_mark, opts \\ %{}) do
        ```

1.  In this commit, the marks<sub>ui</sub> is NOT kept by the read
    context module, that's why when I update things by create mark or
    delete mark, the ui state is not preserved and initial, default
    state is seen. This was intentionally done in this commit because
    I'm having problems with duplicate ids for verses for some reason,
    I'll show it in the next commit, so that the problem can be clearly
    seen.

* [BUGGY] keep marks_ui within ReadContext

This is buggy, not sure why there's a duplicate yet.  will come back to
it after lunch

Replication Steps:
1. delete all marks and see there's no error
2. create first mark ==> no error
3. create second mark ==> crashes due to duplicate verse id

Crash dump:

[debug] Replied in 13ms
[error] GenServer #PID<0.8416.0> terminating
** (RuntimeError) found duplicate ID "verse-7d9d588a-34fc-4f19-b974-fc32b49b6a61" for component VyasaWeb.Context.Read.VerseMatrix when rendering template
    (phoenix_live_view 1.0.0-rc.6) lib/phoenix_live_view/diff.ex:634: anonymous fn/5 in Phoenix.LiveView.Diff.render_pending_components/6
    (elixir 1.17.2) lib/enum.ex:2531: Enum."-reduce/3-lists^foldl/2-0-"/3
    (phoenix_live_view 1.0.0-rc.6) lib/phoenix_live_view/diff.ex:631: anonymous fn/4 in Phoenix.LiveView.Diff.render_pending_components/6
    (stdlib 5.2.3) maps.erl:416: :maps.fold_1/4
    (phoenix_live_view 1.0.0-rc.6) lib/phoenix_live_view/diff.ex:625: Phoenix.LiveView.Diff.render_pending_components/6
    (phoenix_live_view 1.0.0-rc.6) lib/phoenix_live_view/diff.ex:217: Phoenix.LiveView.Diff.write_component/4
    (phoenix_live_view 1.0.0-rc.6) lib/phoenix_live_view/channel.ex:662: Phoenix.LiveView.Channel.component_handle/4
    (stdlib 5.2.3) gen_server.erl:1095: :gen_server.try_handle_info/3
    (stdlib 5.2.3) gen_server.erl:1183: :gen_server.handle_msg/6
    (stdlib 5.2.3) proc_lib.erl:251: :proc_lib.wake_up/3
Last message: %Phoenix.Socket.Message{topic: "lv:phx-F_1MH_6F0ciqVqwi", event: "event", payload: %{"cid" => 3, "event" => "createMark", "type" => "form", "value" => "body=how+about+now%2C+any+duplicate%3F"}, ref: "23", join_ref: "4"}
State: %{socket: #Phoenix.LiveView.Socket<id: "phx-F_1MH_6F0ciqVqwi", endpoint: VyasaWeb.Endpoint, view: VyasaWeb.ModeLive.Mediator, parent_pid: nil, root_pid: #PID<0.8416.0>, router: VyasaWeb.Router, assigns: %{mode: %VyasaWeb.ModeLive.UserMode{mode: "read", default_ui_state: %VyasaWeb.ModeLive.UiState{show_media_bridge?: true, show_action_bar?: true}, mode_icon_name: "hero-book-open", quick_actions: [:mark_quote, :bookmark], control_panel_modes: ["discuss"], mode_actions: [:mark_quote, :bookmark], action_bar_actions: [:nav_back, :nav_fwd], action_bar_info_types: nil, action_bar_component: VyasaWeb.MediaLive.MediaBridge, action_bar_component_selector: "media-bridge", control_panel_component: VyasaWeb.ControlPanel, control_panel_component_selector: "control-panel", mode_context_component: VyasaWeb.Context.Read, mode_context_component_selector: "read"}, session: %VyasaWeb.Session{name: "ritesh kumar", id: "IhrQV0ypqg8bHakbvb2bymNF", active: true, sangh: %Vyasa.Sangh.Session{__meta__: #Ecto.Schema.Metadata<:loaded, "sessions">, id: "164eb05d-221a-4939-b180-8394e1a5515f", sheafs: #Ecto.Association.NotLoaded<association :sheafs is not loaded>, inserted_at: ~U[2024-09-27 00:51:48Z], updated_at: ~U[2024-09-27 00:51:48Z]}, last_opened: "2024-09-23T11:03:32.022987Z"}, __changed__: %{}, flash: %{}, locale: "en-GB", url_params: %{"chap_no" => "1", "source_title" => "hanuman_chalisa"}, live_action: :show_verses, ui_state: %VyasaWeb.ModeLive.UiState{show_media_bridge?: true, show_action_bar?: true}, device_type: :desktop, tz: %{timezone: "Asia/Singapore", timezone_offset: 480}}, transport_pid: #PID<0.8403.0>, ...>, components: {%{15 => {VyasaWeb.Context.Read.VerseMatrix, "verse-aa3ad88b-0de1-443e-b471-c08a44e67c61", %{id: "verse-aa3ad88b-0de1-443e-b471-c08a44e67c61", edge: [%{title: "1.10", field: [:body], verseup: {:big, "dn"}}, %{node: %Vyasa.Written.Translation{__meta__: #Ecto.Schema.Metadata<:loaded, "translations">, id: "651676b6-ffc3-41c1-b525-f376989f639e", lang: "en", type: "verses", target: %Vyasa.Written.Translation.Target{id: "dd20a94f-8f34-49f8-8da8-4321cfecf172", title: nil, title_translit: nil, body: "प्रभु चरित्र सुनिबे को रसिया ।\n\nराम लखन सीता मन बसिया ॥८॥", body_meant: nil, body_translit: "prabhu caritra sunibe ko rasiyā .\n\nrāma lakhana sītā mana basiyā ..8..", body_translit_meant: "You feel extremely delighted in listening to Lord Rama’s doings and conduct. Lord Rama, Mother Sita, and Lord Laxmana dwell forever in your heart."}, verse_id: "aa3ad88b-0de1-443e-b471-c08a44e67c61", verse: #Ecto.Association.NotLoaded<association :verse is not loaded>, chapter_no: nil, chapter: #Ecto.Association.NotLoaded<association :chapter is not loaded>, source_id: "63918acd-77a9-451a-b8d1-8d5b73208eae", source: #Ecto.Association.NotLoaded<association :source is not loaded>}, field: [:target, :body_translit], verseup: :mid}, %{node: %Vyasa.Written.Translation{__meta__: #Ecto.Schema.Metadata<:loaded, "translations">, id: "651676b6-ffc3-41c1-b525-f376989f639e", lang: "en", type: "verses", target: %Vyasa.Written.Translation.Target{id: "dd20a94f-8f34-49f8-8da8-4321cfecf172", title: nil, title_translit: nil, body: "प्रभु चरित्र सुनिबे को रसिया ।\n\nराम लखन सीता मन बसिया ॥८॥", body_meant: nil, body_translit: "prabhu caritra sunibe ko rasiyā .\n\nrāma lakhana sītā mana basiyā ..8..", body_translit_meant: "You feel extremely delighted in listening to Lord Rama’s doings and conduct. Lord Rama, Mother Sita, and Lord Laxmana dwell forever in your heart."}, verse_id: "aa3ad88b-0de1-443e-b471-c08a44e67c61", verse: #Ecto.Association.NotLoaded<association :verse is not loaded>, chapter_no: nil, chapter: #Ecto.Association.NotLoaded<association :chapter is not loaded>, source_id: "63918acd-77a9-451a-b8d1-8d5b73208eae", source: #Ecto.Association.NotLoaded<association :source is not loaded>}, field: [:target, :body_translit_meant], verseup: :mid}, %{node: %Vyasa.Written.Translation{__meta__: #Ecto.Schema.Metadata<:loaded, "translations">, id: "651676b6-ffc3-41c1-b525-f376989f639e", lang: "en", type: "verses", target: %Vyasa.Written.Translation.Target{id: "dd20a94f-8f34-49f8-8da8-4321cfecf172", title: nil, title_translit: nil, body: "प्रभु चरित्र सुनिबे को रसिया ।\n\nराम लखन सीता मन बसिया ॥८॥", body_meant: nil, body_translit: "prabhu caritra sunibe ko rasiyā .\n\nrāma lakhana sītā mana basiyā ..8..", body_translit_meant: "You feel extremely delighted in listening to Lord Rama’s doings and conduct. Lord Rama, Mother Sita, and Lord Laxmana dwell forever in your heart."}, verse_id: "aa3ad88b-0de1-443e-b471-c08a44e67c61", verse: #Ecto.Association.NotLoaded<association :verse is not loaded>, chapter_no: nil, chapter: #Ecto.Association.NotLoaded<association :chapter is not loaded>, source_id: "63918acd-77a9-451a-b8d1-8d5b73208eae", source: #Ecto.Association.NotLoaded<association :source is not loaded>}, field: [:target, :body], verseup: :mid}], __changed__: %{}, flash: %{}, marks: [%Vyasa.Sangh.Mark{__meta__: #Ecto.Schema.Metadata<:loaded, "marks">, id: "5dfdb167-6c57-46dd-a0c4-10b52cb03a85", body: "wonderful", order: 2, state: :live, verse_id: nil, sheaf_id: "7f4ab16b-0caf-4009-ba2a-3ddded81d9aa", sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>, binding_id: "001da594-3808-46cf-9b9c-5dfb3559780e", binding: %Vyasa.Adapters.Binding{__meta__: #Ecto.Schema.Metadata<:loaded, "bindings">, id: "001da594-3808-46cf-9b9c-5dfb3559780e", w_type: nil, field_key: ["target", "body_translit_meant"], node_id: nil, verse_id: nil, verse: #Ecto.Association.NotLoaded<association :verse is not loaded>, chapter_no: nil, chapter: #Ecto.Association.NotLoaded<association :chapter is not loaded>, source_id: nil, source: #Ecto.Association.NotLoaded<association :source is not loaded>, translation_id: "97a7a662-a91b-486f-93e8-7ae932d01a1a", translation: #Ecto.Association.NotLoaded<association :translation is not loaded>, sheaf_id: nil, sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>, window: nil}, inserted_at: ~U[2024-10-11 04:31:50Z], updated_at: ~U[2024-10-11 04:31:50Z]}, %Vyasa.Sangh.Mark{__meta__: #Ecto.Schema.Metadata<:loaded, "marks">, id: "273a093d-4f90-40a4-b19a-2f8f7825d201", body: "truncated utc datetime", order: 1, state: :live, verse_id: nil, sheaf_id: "7f4ab16b-0caf-4009-ba2a-3ddded81d9aa", sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>, binding_id: "ef39315b-530c-4841-ba32-86773f451727", binding: %Vyasa.Adapt (truncated)
[debug] MOUNT VyasaWeb.ModeLive.Mediator
  Parameters: %{"chap_no" => "1", "source_title" => "hanuman_chalisa"}
  Session: %{"_csrf_token" => "DJ-RIoXwEzHW82rbb21le_8k"}
[debug] QUERY OK source="sessions" db=3.5ms idle=1690.4ms
SELECT s0."id", s0."inserted_at", s0."updated_at" FROM "sessions" AS s0 WHERE (s0."id" = $1) ["164eb05d-221a-4939-b180-8394e1a5515f"]
↳

* Fix duplicate id issue on verse matrix

* Standardise use of @event_target, cleanups

When using @event_target, the intent is that phx-target values
will be passed around. This must be agnostic to the 2 main ways of
supplying that argument, as a HTML selector, or as a module name (or @myself).
Therefore, we should discourage ourselves from doing format-strings at
the point of the @event_target being supplied as an argument, meaning:

good, because agnostic:
phx-target={@event_target}

bad, because hardcoded:
phx-target={"#" <> @event_target}
* in this case, the event trigger will throw a dom error.

* [Attempt]: Sanitise, defrag orders in marks-list

If this is an anti-pattern, then this commit should be reverted.

* UI fixes: hide buttons on marks when !is_editable?

* Add in stub event handlers to prevent crashes

Temporary stuff, will be addressed in immediate-next PR

* Minor changes

* Toggle edit state for marks content

* Partial implementation of edit marks

the form stuff doesn't exist so it's not wired up yet. To be frank,
im' not sure how to set up a form without it needing to hold state.

* [BUGGY] Wire up form update for edit

this does the following:
1. wires up the form like how we usedd it in createMark
2. actually captures the event properly within the event handler,
everything looks good at that point, even the edit_mark_in_marks
function on inspection looks good
3. the marks is getting assigned to properly because the newly edited
mark content is seen after doing a dom refresh
4. HOWEVER, the print statement at the sheaf_update function DOES NOT
show the correct, updated marks in the sheaf

here's a dump for it for reference

[debug] HANDLE EVENT "editMarkContent" in VyasaWeb.ModeLive.Mediator
  Component: VyasaWeb.Context.Read
  Parameters: %{"mark_id" => "02218551-591f-4450-abbd-a7b7d76fd48e"}
[debug] Replied in 2ms
[debug] HANDLE EVENT "editMarkContent" in VyasaWeb.ModeLive.Mediator
  Component: VyasaWeb.Context.Read
  Parameters: %{"mark_body" => "  testing\n\n\nwhat hte heck", "mark_id" => "02218551-591f-4450-abbd-a7b7d76fd48e"}
>>> UPDATE SHEAF -- SHOULD BE WRITING TO DB NOW: %Vyasa.Sangh.Sheaf{
  __meta__: #Ecto.Schema.Metadata<:loaded, "sheafs">,
  id: "7f4ab16b-0caf-4009-ba2a-3ddded81d9aa",
  body: nil,
  active: true,
  path: %EctoLtree.LabelTree{labels: ["7f4ab16b"]},
  signature: nil,
  traits: ["draft"],
  child_count: 0,
  session_id: "164eb05d-221a-4939-b180-8394e1a5515f",
  session: #Ecto.Association.NotLoaded<association :session is not loaded>,
  parent_id: nil,
  parent: #Ecto.Association.NotLoaded<association :parent is not loaded>,
  marks: [
    %Vyasa.Sangh.Mark{
      __meta__: #Ecto.Schema.Metadata<:loaded, "marks">,
      id: "555eb625-e392-496e-9831-4f4c130be6fd",
      body: "wonderful stuff",
      order: 5,
      state: :live,
      verse_id: nil,
      sheaf_id: "7f4ab16b-0caf-4009-ba2a-3ddded81d9aa",
      sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>,
      binding_id: "072124d0-5e27-4601-832f-35eaa6426879",
      binding: %Vyasa.Adapters.Binding{
        __meta__: #Ecto.Schema.Metadata<:loaded, "bindings">,
        id: "072124d0-5e27-4601-832f-35eaa6426879",
        w_type: nil,
        field_key: ["target", "body_translit_meant"],
        node_id: nil,
        verse_id: nil,
        verse: #Ecto.Association.NotLoaded<association :verse is not loaded>,
        chapter_no: nil,
        chapter: #Ecto.Association.NotLoaded<association :chapter is not loaded>,
        source_id: nil,
        source: #Ecto.Association.NotLoaded<association :source is not loaded>,
        translation_id: "97a7a662-a91b-486f-93e8-7ae932d01a1a",
        translation: #Ecto.Association.NotLoaded<association :translation is not loaded>,
        sheaf_id: nil,
        sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>,
        window: nil
      },
      inserted_at: ~U[2024-10-12 08:46:54Z],
      updated_at: ~U[2024-10-12 08:46:54Z]
    },
    %Vyasa.Sangh.Mark{
      __meta__: #Ecto.Schema.Metadata<:loaded, "marks">,
      id: "b22a5661-8268-4875-be26-a12256414136",
      body: nil,
      order: 5,
      state: :draft,
      verse_id: nil,
      sheaf_id: "7f4ab16b-0caf-4009-ba2a-3ddded81d9aa",
      sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>,
      binding_id: "90e18044-73b2-4ede-a149-a381de893b9f",
      binding: %Vyasa.Adapters.Binding{
        __meta__: #Ecto.Schema.Metadata<:loaded, "bindings">,
        id: "90e18044-73b2-4ede-a149-a381de893b9f",
        w_type: nil,
        field_key: ["target", "body_translit_meant"],
        node_id: nil,
        verse_id: nil,
        verse: #Ecto.Association.NotLoaded<association :verse is not loaded>,
        chapter_no: nil,
        chapter: #Ecto.Association.NotLoaded<association :chapter is not loaded>,
        source_id: nil,
        source: #Ecto.Association.NotLoaded<association :source is not loaded>,
        translation_id: "fc80709a-39dc-4b9c-95c3-1d64ce818302",
        translation: #Ecto.Association.NotLoaded<association :translation is not loaded>,
        sheaf_id: nil,
        sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>,
        window: nil
      },
      inserted_at: ~U[2024-10-12 09:52:40Z],
      updated_at: ~U[2024-10-12 09:52:40Z]
    },
    %Vyasa.Sangh.Mark{
      __meta__: #Ecto.Schema.Metadata<:loaded, "marks">,
      id: "8af43833-575c-4eb8-83b1-eb4e58509e4c",
      body: nil,
      order: 4,
      state: :draft,
      verse_id: nil,
      sheaf_id: "7f4ab16b-0caf-4009-ba2a-3ddded81d9aa",
      sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>,
      binding_id: "23b70937-ed81-47fe-a560-ee14287bff7d",
      binding: %Vyasa.Adapters.Binding{
        __meta__: #Ecto.Schema.Metadata<:loaded, "bindings">,
        id: "23b70937-ed81-47fe-a560-ee14287bff7d",
        w_type: nil,
        field_key: ["target", "body_translit_meant"],
        node_id: nil,
        verse_id: nil,
        verse: #Ecto.Association.NotLoaded<association :verse is not loaded>,
        chapter_no: nil,
        chapter: #Ecto.Association.NotLoaded<association :chapter is not loaded>,
        source_id: nil,
        source: #Ecto.Association.NotLoaded<association :source is not loaded>,
        translation_id: "97a7a662-a91b-486f-93e8-7ae932d01a1a",
        translation: #Ecto.Association.NotLoaded<association :translation is not loaded>,
        sheaf_id: nil,
        sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>,
        window: nil
      },
      inserted_at: ~U[2024-10-12 09:46:13Z],
      updated_at: ~U[2024-10-12 09:46:13Z]
    },
    %Vyasa.Sangh.Mark{
      __meta__: #Ecto.Schema.Metadata<:loaded, "marks">,
      id: "c7ad47e6-629d-4382-936d-64d757772c4e",
      body: nil,
      order: 3,
      state: :draft,
      verse_id: nil,
      sheaf_id: "7f4ab16b-0caf-4009-ba2a-3ddded81d9aa",
      sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>,
      binding_id: "d5758230-7966-4f9b-8c16-ae13998cd71b",
      binding: %Vyasa.Adapters.Binding{
        __meta__: #Ecto.Schema.Metadata<:loaded, "bindings">,
        id: "d5758230-7966-4f9b-8c16-ae13998cd71b",
        w_type: nil,
        field_key: ["target", "body_translit_meant"],
        node_id: nil,
        verse_id: nil,
        verse: #Ecto.Association.NotLoaded<association :verse is not loaded>,
        chapter_no: nil,
        chapter: #Ecto.Association.NotLoaded<association :chapter is not loaded>,
        source_id: nil,
        source: #Ecto.Association.NotLoaded<association :source is not loaded>,
        translation_id: "fc80709a-39dc-4b9c-95c3-1d64ce818302",
        translation: #Ecto.Association.NotLoaded<association :translation is not loaded>,
        sheaf_id: nil,
        sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>,
        window: nil
      },
      inserted_at: ~U[2024-10-12 09:44:09Z],
      updated_at: ~U[2024-10-12 09:44:09Z]
    },
    %Vyasa.Sangh.Mark{
      __meta__: #Ecto.Schema.Metadata<:loaded, "marks">,
      id: "02218551-591f-4450-abbd-a7b7d76fd48e",
      body: "testing",
      order: 2,
      state: :live,
      verse_id: nil,
      sheaf_id: "7f4ab16b-0caf-4009-ba2a-3ddded81d9aa",
      sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>,
      binding_id: "19ffdc82-a5d8-49c3-8b01-1559736dad80",
      binding: %Vyasa.Adapters.Binding{
        __meta__: #Ecto.Schema.Metadata<:loaded, "bindings">,
        id: "19ffdc82-a5d8-49c3-8b01-1559736dad80",
        w_type: nil,
        field_key: ["target", "body_translit_meant"],
        node_id: nil,
        verse_id: nil,
        verse: #Ecto.Association.NotLoaded<association :verse is not loaded>,
        chapter_no: nil,
        chapter: #Ecto.Association.NotLoaded<association :chapter is not loaded>,
        source_id: nil,
        source: #Ecto.Association.NotLoaded<association :source is not loaded>,
        translation_id: "fc80709a-39dc-4b9c-95c3-1d64ce818302",
        translation: #Ecto.Association.NotLoaded<association :translation is not loaded>,
        sheaf_id: nil,
        sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>,
        window: nil
      },
      inserted_at: ~U[2024-10-12 09:43:19Z],
      updated_at: ~U[2024-10-12 09:43:19Z]
    },
    %Vyasa.Sangh.Mark{
      __meta__: #Ecto.Schema.Metadata<:loaded, "marks">,
      id: "90c6036a-9bd1-4b65-82d5-f121ec4d7867",
      body: nil,
      order: 2,
      state: :draft,
      verse_id: nil,
      sheaf_id: "7f4ab16b-0caf-4009-ba2a-3ddded81d9aa",
      sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>,
      binding_id: "b92f990d-99a2-4f04-a2d4-d1135021ee8c",
      binding: %Vyasa.Adapters.Binding{
        __meta__: #Ecto.Schema.Metadata<:loaded, "bindings">,
        id: "b92f990d-99a2-4f04-a2d4-d1135021ee8c",
        w_type: nil,
        field_key: ["target", "body_translit_meant"],
        node_id: nil,
        verse_id: nil,
        verse: #Ecto.Association.NotLoaded<association :verse is not loaded>,
        chapter_no: nil,
        chapter: #Ecto.Association.NotLoaded<association :chapter is not loaded>,
        source_id: nil,
        source: #Ecto.Association.NotLoaded<association :source is not loaded>,
        translation_id: "97a7a662-a91b-486f-93e8-7ae932d01a1a",
        translation: #Ecto.Association.NotLoaded<association :translation is not loaded>,
        sheaf_id: nil,
        sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>,
        window: nil
      },
      inserted_at: ~U[2024-10-11 09:03:00Z],
      updated_at: ~U[2024-10-11 09:03:00Z]
    }
  ],
  inserted_at: ~N[2024-09-27 00:51:48],
  updated_at: ~N[2024-09-27 00:51:48]
}
[debug] Replied in 81ms
[debug] HANDLE EVENT "verses::focus_toggle_on_quick_mark_drafting" in VyasaWeb.ModeLive.Mediator
  Component: VyasaWeb.Context.Read
  Parameters: %{"is_focusing?" => false, "value" => ""}
[debug] Replied in 129µs
iex([email protected])17>

* marks order force

* old man mark is not feeling so good

* ReWrite how marks get initialised @ :show_verse (#119)

* Minor change in fn signature

* Add init_draft_reflector()

* Don't rely on the time async message passing

* Use custom generic_modal_wrapper

This one has more specific callback attributes and tailwind classes can
be injected to it.

* Create data and ui skeletons for sheaf_creator

* Add support for human friendly time formatting

* Setup skeleton for replyto context

Some pending todo functions for how the reply to context shall be determined

* Standardise UI, improve wrapper's default UI

* Improve generic_modal_wrapper styling slots

* Wire sheaf creation form to stubbed event handler

Relevant TODOs have been added

* Use session.name for signature, add handler stubs

* Edit marks in read mode (#118)

* Add generic debug dump component

This makes life easy when wiring things up

* Rename namespace for Context.Read.*

* Groundwork: add discuss component w sheafs

* Init Context.Components mod for common components

* Add skeletons for Sheaf Container

Container managers sheaf state within itself.
Should actually make the verse-matrix use this container, sometime.

* Minor changes, add some TODOs to share

explicit todos

Minor change

* Add live component EditableMarkDisplay

* Add UI improvements to EditableMarkDisplay

The edit button on quick draft should only be seen when the dropdown is
expanded and all the marks can be seen. The general pattern I'm trying
to follow is that buttons should only be shown when an action makes
sense. So here, if the user can't even see the marks currently
accumulating, then the user shouldn't have the chance to edit any marks.

Notice that the EditableMarkDisplay is a live_component that is a child
of a function component (collapsible_marks_display). This is so that it can keep its own state and
do it's own event-handling. I'm not sure if this is pattern-breaking.
A reference to the actual parent live_component that calls collapsible_marks_display
will always be there in case there's a need for the parent to handle
any particular events. So comms b/w live_components is still going to be
via phx-target values.

* Change <input/> -> <textarea/> fr quick_draft_form

* Add tailwind config for custom svg icons

not sure how the scaling for this works, seems like i can't just put in
the class="h-5 w-5" to do the scaling

* Let custom svg be scalable

* Subtly shift the ping indicator to control panel

* Marks ordering in Sheaf and L-Trees  (#114)

* do sheafs grow on trees

* sangh session dealing with lineage

* Solve initial order problem

* fix: ensure non-null id used @ EditableMarkDisplay

---------

Co-authored-by: ks0m1c_dharma <[email protected]>

* Trigger Diff

* TOMBSTONING

* Fix bugs and revert ui for read_mode:delete marks

1.  JIT generate id for marks yet to be inserted to the db: instead of
    using a temp id, I'm actually assigning a JIT-generated id for a
    mark even if that isn't inserted into the db yet. this has two
    benefits: div ids have meaningful static ids (e.g.
    mark-container-\<\> mark.id) regardless of whether that mark has
    been inserted into the db or not. While doing this, the changeset
    for marks has been udpated to add id as well. This fixes a bunch of
    id-based errors as well.

2.  while doing 1, it came to light that the bindHoverune handlers were
    not handling the draft mark update properly (i.e. not using the
    already existing update function in mark) . it's changed now,
    example of the diff:

    ``` diff
      @impl true
      def handle_event(
            "bindHoveRune",
            %{"binding" => bind = %{"verse_id" => verse_id}},
            %{
              assigns: %{
                kv_verses: verses,
                marks: [%Mark{state: :draft, verse_id: curr_verse_id} = d_mark | marks]
              }
            } = socket
          )
          when is_binary(curr_verse_id) and verse_id != curr_verse_id do
        # binding here blocks the stream from appending to quote
        bind = Draft.bind_node(bind)

        bound_verses =
          verses
           |> then(&put_in(&1[verse_id].binding, bind))
           |> then(&put_in(&1[curr_verse_id].binding, nil))

    +    updated_draft_mark = d_mark |> Mark.update_mark(%{binding: bind, verse_id: verse_id})
    +
         {:noreply,
          socket
          |> mutate_verses(curr_verse_id, bound_verses)
          |> mutate_verses(verse_id, bound_verses)
    -     |> assign(:marks, [%{d_mark | binding: bind, verse_id: verse_id} | marks])}
    +     |> assign(:marks, [updated_draft_mark | marks])}
       end
    ```

3.  add ui state structs: all of the relevant ui states have structs
    that are intended to be static interfaces. this felt better than
    directly keeping state within various sockets and is done with a
    view to remove live components and change them to function
    components wherever possible.

4.  bugfix for `order()`:

    - it had an off-by-one-error
    - shifted it to Vyasa.Sangh.Mark
    - also note that the order shall be 1-indexed instead of 0-indexed
      for human-friendliness

5.  minor fixes:

    1.  fix update<sub>mark</sub> default argument

        ``` diff
        -def update_mark(%Mark{} = draft_mark, opts \\ []) do
        +def update_mark(%Mark{} = draft_mark, opts \\ %{}) do
        ```

1.  In this commit, the marks<sub>ui</sub> is NOT kept by the read
    context module, that's why when I update things by create mark or
    delete mark, the ui state is not preserved and initial, default
    state is seen. This was intentionally done in this commit because
    I'm having problems with duplicate ids for verses for some reason,
    I'll show it in the next commit, so that the problem can be clearly
    seen.

* [BUGGY] keep marks_ui within ReadContext

This is buggy, not sure why there's a duplicate yet.  will come back to
it after lunch

Replication Steps:
1. delete all marks and see there's no error
2. create first mark ==> no error
3. create second mark ==> crashes due to duplicate verse id

Crash dump:

[debug] Replied in 13ms
[error] GenServer #PID<0.8416.0> terminating
** (RuntimeError) found duplicate ID "verse-7d9d588a-34fc-4f19-b974-fc32b49b6a61" for component VyasaWeb.Context.Read.VerseMatrix when rendering template
    (phoenix_live_view 1.0.0-rc.6) lib/phoenix_live_view/diff.ex:634: anonymous fn/5 in Phoenix.LiveView.Diff.render_pending_components/6
    (elixir 1.17.2) lib/enum.ex:2531: Enum."-reduce/3-lists^foldl/2-0-"/3
    (phoenix_live_view 1.0.0-rc.6) lib/phoenix_live_view/diff.ex:631: anonymous fn/4 in Phoenix.LiveView.Diff.render_pending_components/6
    (stdlib 5.2.3) maps.erl:416: :maps.fold_1/4
    (phoenix_live_view 1.0.0-rc.6) lib/phoenix_live_view/diff.ex:625: Phoenix.LiveView.Diff.render_pending_components/6
    (phoenix_live_view 1.0.0-rc.6) lib/phoenix_live_view/diff.ex:217: Phoenix.LiveView.Diff.write_component/4
    (phoenix_live_view 1.0.0-rc.6) lib/phoenix_live_view/channel.ex:662: Phoenix.LiveView.Channel.component_handle/4
    (stdlib 5.2.3) gen_server.erl:1095: :gen_server.try_handle_info/3
    (stdlib 5.2.3) gen_server.erl:1183: :gen_server.handle_msg/6
    (stdlib 5.2.3) proc_lib.erl:251: :proc_lib.wake_up/3
Last message: %Phoenix.Socket.Message{topic: "lv:phx-F_1MH_6F0ciqVqwi", event: "event", payload: %{"cid" => 3, "event" => "createMark", "type" => "form", "value" => "body=how+about+now%2C+any+duplicate%3F"}, ref: "23", join_ref: "4"}
State: %{socket: #Phoenix.LiveView.Socket<id: "phx-F_1MH_6F0ciqVqwi", endpoint: VyasaWeb.Endpoint, view: VyasaWeb.ModeLive.Mediator, parent_pid: nil, root_pid: #PID<0.8416.0>, router: VyasaWeb.Router, assigns: %{mode: %VyasaWeb.ModeLive.UserMode{mode: "read", default_ui_state: %VyasaWeb.ModeLive.UiState{show_media_bridge?: true, show_action_bar?: true}, mode_icon_name: "hero-book-open", quick_actions: [:mark_quote, :bookmark], control_panel_modes: ["discuss"], mode_actions: [:mark_quote, :bookmark], action_bar_actions: [:nav_back, :nav_fwd], action_bar_info_types: nil, action_bar_component: VyasaWeb.MediaLive.MediaBridge, action_bar_component_selector: "media-bridge", control_panel_component: VyasaWeb.ControlPanel, control_panel_component_selector: "control-panel", mode_context_component: VyasaWeb.Context.Read, mode_context_component_selector: "read"}, session: %VyasaWeb.Session{name: "ritesh kumar", id: "IhrQV0ypqg8bHakbvb2bymNF", active: true, sangh: %Vyasa.Sangh.Session{__meta__: #Ecto.Schema.Metadata<:loaded, "sessions">, id: "164eb05d-221a-4939-b180-8394e1a5515f", sheafs: #Ecto.Association.NotLoaded<association :sheafs is not loaded>, inserted_at: ~U[2024-09-27 00:51:48Z], updated_at: ~U[2024-09-27 00:51:48Z]}, last_opened: "2024-09-23T11:03:32.022987Z"}, __changed__: %{}, flash: %{}, locale: "en-GB", url_params: %{"chap_no" => "1", "source_title" => "hanuman_chalisa"}, live_action: :show_verses, ui_state: %VyasaWeb.ModeLive.UiState{show_media_bridge?: true, show_action_bar?: true}, device_type: :desktop, tz: %{timezone: "Asia/Singapore", timezone_offset: 480}}, transport_pid: #PID<0.8403.0>, ...>, components: {%{15 => {VyasaWeb.Context.Read.VerseMatrix, "verse-aa3ad88b-0de1-443e-b471-c08a44e67c61", %{id: "verse-aa3ad88b-0de1-443e-b471-c08a44e67c61", edge: [%{title: "1.10", field: [:body], verseup: {:big, "dn"}}, %{node: %Vyasa.Written.Translation{__meta__: #Ecto.Schema.Metadata<:loaded, "translations">, id: "651676b6-ffc3-41c1-b525-f376989f639e", lang: "en", type: "verses", target: %Vyasa.Written.Translation.Target{id: "dd20a94f-8f34-49f8-8da8-4321cfecf172", title: nil, title_translit: nil, body: "प्रभु चरित्र सुनिबे को रसिया ।\n\nराम लखन सीता मन बसिया ॥८॥", body_meant: nil, body_translit: "prabhu caritra sunibe ko rasiyā .\n\nrāma lakhana sītā mana basiyā ..8..", body_translit_meant: "You feel extremely delighted in listening to Lord Rama’s doings and conduct. Lord Rama, Mother Sita, and Lord Laxmana dwell forever in your heart."}, verse_id: "aa3ad88b-0de1-443e-b471-c08a44e67c61", verse: #Ecto.Association.NotLoaded<association :verse is not loaded>, chapter_no: nil, chapter: #Ecto.Association.NotLoaded<association :chapter is not loaded>, source_id: "63918acd-77a9-451a-b8d1-8d5b73208eae", source: #Ecto.Association.NotLoaded<association :source is not loaded>}, field: [:target, :body_translit], verseup: :mid}, %{node: %Vyasa.Written.Translation{__meta__: #Ecto.Schema.Metadata<:loaded, "translations">, id: "651676b6-ffc3-41c1-b525-f376989f639e", lang: "en", type: "verses", target: %Vyasa.Written.Translation.Target{id: "dd20a94f-8f34-49f8-8da8-4321cfecf172", title: nil, title_translit: nil, body: "प्रभु चरित्र सुनिबे को रसिया ।\n\nराम लखन सीता मन बसिया ॥८॥", body_meant: nil, body_translit: "prabhu caritra sunibe ko rasiyā .\n\nrāma lakhana sītā mana basiyā ..8..", body_translit_meant: "You feel extremely delighted in listening to Lord Rama’s doings and conduct. Lord Rama, Mother Sita, and Lord Laxmana dwell forever in your heart."}, verse_id: "aa3ad88b-0de1-443e-b471-c08a44e67c61", verse: #Ecto.Association.NotLoaded<association :verse is not loaded>, chapter_no: nil, chapter: #Ecto.Association.NotLoaded<association :chapter is not loaded>, source_id: "63918acd-77a9-451a-b8d1-8d5b73208eae", source: #Ecto.Association.NotLoaded<association :source is not loaded>}, field: [:target, :body_translit_meant], verseup: :mid}, %{node: %Vyasa.Written.Translation{__meta__: #Ecto.Schema.Metadata<:loaded, "translations">, id: "651676b6-ffc3-41c1-b525-f376989f639e", lang: "en", type: "verses", target: %Vyasa.Written.Translation.Target{id: "dd20a94f-8f34-49f8-8da8-4321cfecf172", title: nil, title_translit: nil, body: "प्रभु चरित्र सुनिबे को रसिया ।\n\nराम लखन सीता मन बसिया ॥८॥", body_meant: nil, body_translit: "prabhu caritra sunibe ko rasiyā .\n\nrāma lakhana sītā mana basiyā ..8..", body_translit_meant: "You feel extremely delighted in listening to Lord Rama’s doings and conduct. Lord Rama, Mother Sita, and Lord Laxmana dwell forever in your heart."}, verse_id: "aa3ad88b-0de1-443e-b471-c08a44e67c61", verse: #Ecto.Association.NotLoaded<association :verse is not loaded>, chapter_no: nil, chapter: #Ecto.Association.NotLoaded<association :chapter is not loaded>, source_id: "63918acd-77a9-451a-b8d1-8d5b73208eae", source: #Ecto.Association.NotLoaded<association :source is not loaded>}, field: [:target, :body], verseup: :mid}], __changed__: %{}, flash: %{}, marks: [%Vyasa.Sangh.Mark{__meta__: #Ecto.Schema.Metadata<:loaded, "marks">, id: "5dfdb167-6c57-46dd-a0c4-10b52cb03a85", body: "wonderful", order: 2, state: :live, verse_id: nil, sheaf_id: "7f4ab16b-0caf-4009-ba2a-3ddded81d9aa", sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>, binding_id: "001da594-3808-46cf-9b9c-5dfb3559780e", binding: %Vyasa.Adapters.Binding{__meta__: #Ecto.Schema.Metadata<:loaded, "bindings">, id: "001da594-3808-46cf-9b9c-5dfb3559780e", w_type: nil, field_key: ["target", "body_translit_meant"], node_id: nil, verse_id: nil, verse: #Ecto.Association.NotLoaded<association :verse is not loaded>, chapter_no: nil, chapter: #Ecto.Association.NotLoaded<association :chapter is not loaded>, source_id: nil, source: #Ecto.Association.NotLoaded<association :source is not loaded>, translation_id: "97a7a662-a91b-486f-93e8-7ae932d01a1a", translation: #Ecto.Association.NotLoaded<association :translation is not loaded>, sheaf_id: nil, sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>, window: nil}, inserted_at: ~U[2024-10-11 04:31:50Z], updated_at: ~U[2024-10-11 04:31:50Z]}, %Vyasa.Sangh.Mark{__meta__: #Ecto.Schema.Metadata<:loaded, "marks">, id: "273a093d-4f90-40a4-b19a-2f8f7825d201", body: "truncated utc datetime", order: 1, state: :live, verse_id: nil, sheaf_id: "7f4ab16b-0caf-4009-ba2a-3ddded81d9aa", sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>, binding_id: "ef39315b-530c-4841-ba32-86773f451727", binding: %Vyasa.Adapt (truncated)
[debug] MOUNT VyasaWeb.ModeLive.Mediator
  Parameters: %{"chap_no" => "1", "source_title" => "hanuman_chalisa"}
  Session: %{"_csrf_token" => "DJ-RIoXwEzHW82rbb21le_8k"}
[debug] QUERY OK source="sessions" db=3.5ms idle=1690.4ms
SELECT s0."id", s0."inserted_at", s0."updated_at" FROM "sessions" AS s0 WHERE (s0."id" = $1) ["164eb05d-221a-4939-b180-8394e1a5515f"]
↳

* Fix duplicate id issue on verse matrix

* Standardise use of @event_target, cleanups

When using @event_target, the intent is that phx-target values
will be passed around. This must be agnostic to the 2 main ways of
supplying that argument, as a HTML selector, or as a module name (or @myself).
Therefore, we should discourage ourselves from doing format-strings at
the point of the @event_target being supplied as an argument, meaning:

good, because agnostic:
phx-target={@event_target}

bad, because hardcoded:
phx-target={"#" <> @event_target}
* in this case, the event trigger will throw a dom error.

* [Attempt]: Sanitise, defrag orders in marks-list

If this is an anti-pattern, then this commit should be reverted.

* UI fixes: hide buttons on marks when !is_editable?

* Add in stub event handlers to prevent crashes

Temporary stuff, will be addressed in immediate-next PR

* Minor changes

* Toggle edit state for marks content

* Partial implementation of edit marks

the form stuff doesn't exist so it's not wired up yet. To be frank,
im' not sure how to set up a form without it needing to hold state.

* [BUGGY] Wire up form update for edit

this does the following:
1. wires up the form like how we usedd it in createMark
2. actually captures the event properly within the event handler,
everything looks good at that point, even the edit_mark_in_marks
function on inspection looks good
3. the marks is getting assigned to properly because the newly edited
mark content is seen after doing a dom refresh
4. HOWEVER, the print statement at the sheaf_update function DOES NOT
show the correct, updated marks in the sheaf

here's a dump for it for reference

[debug] HANDLE EVENT "editMarkContent" in VyasaWeb.ModeLive.Mediator
  Component: VyasaWeb.Context.Read
  Parameters: %{"mark_id" => "02218551-591f-4450-abbd-a7b7d76fd48e"}
[debug] Replied in 2ms
[debug] HANDLE EVENT "editMarkContent" in VyasaWeb.ModeLive.Mediator
  Component: VyasaWeb.Context.Read
  Parameters: %{"mark_body" => "  testing\n\n\nwhat hte heck", "mark_id" => "02218551-591f-4450-abbd-a7b7d76fd48e"}
>>> UPDATE SHEAF -- SHOULD BE WRITING TO DB NOW: %Vyasa.Sangh.Sheaf{
  __meta__: #Ecto.Schema.Metadata<:loaded, "sheafs">,
  id: "7f4ab16b-0caf-4009-ba2a-3ddded81d9aa",
  body: nil,
  active: true,
  path: %EctoLtree.LabelTree{labels: ["7f4ab16b"]},
  signature: nil,
  traits: ["draft"],
  child_count: 0,
  session_id: "164eb05d-221a-4939-b180-8394e1a5515f",
  session: #Ecto.Association.NotLoaded<association :session is not loaded>,
  parent_id: nil,
  parent: #Ecto.Association.NotLoaded<association :parent is not loaded>,
  marks: [
    %Vyasa.Sangh.Mark{
      __meta__: #Ecto.Schema.Metadata<:loaded, "marks">,
      id: "555eb625-e392-496e-9831-4f4c130be6fd",
      body: "wonderful stuff",
      order: 5,
      state: :live,
      verse_id: nil,
      sheaf_id: "7f4ab16b-0caf-4009-ba2a-3ddded81d9aa",
      sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>,
      binding_id: "072124d0-5e27-4601-832f-35eaa6426879",
      binding: %Vyasa.Adapters.Binding{
        __meta__: #Ecto.Schema.Metadata<:loaded, "bindings">,
        id: "072124d0-5e27-4601-832f-35eaa6426879",
        w_type: nil,
        field_key: ["target", "body_translit_meant"],
        node_id: nil,
        verse_id: nil,
        verse: #Ecto.Association.NotLoaded<association :verse is not loaded>,
        chapter_no: nil,
        chapter: #Ecto.Association.NotLoaded<association :chapter is not loaded>,
        source_id: nil,
        source: #Ecto.Association.NotLoaded<association :source is not loaded>,
        translation_id: "97a7a662-a91b-486f-93e8-7ae932d01a1a",
        translation: #Ecto.Association.NotLoaded<association :translation is not loaded>,
        sheaf_id: nil,
        sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>,
        window: nil
      },
      inserted_at: ~U[2024-10-12 08:46:54Z],
      updated_at: ~U[2024-10-12 08:46:54Z]
    },
    %Vyasa.Sangh.Mark{
      __meta__: #Ecto.Schema.Metadata<:loaded, "marks">,
      id: "b22a5661-8268-4875-be26-a12256414136",
      body: nil,
      order: 5,
      state: :draft,
      verse_id: nil,
      sheaf_id: "7f4ab16b-0caf-4009-ba2a-3ddded81d9aa",
      sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>,
      binding_id: "90e18044-73b2-4ede-a149-a381de893b9f",
      binding: %Vyasa.Adapters.Binding{
        __meta__: #Ecto.Schema.Metadata<:loaded, "bindings">,
        id: "90e18044-73b2-4ede-a149-a381de893b9f",
        w_type: nil,
        field_key: ["target", "body_translit_meant"],
        node_id: nil,
        verse_id: nil,
        verse: #Ecto.Association.NotLoaded<association :verse is not loaded>,
        chapter_no: nil,
        chapter: #Ecto.Association.NotLoaded<association :chapter is not loaded>,
        source_id: nil,
        source: #Ecto.Association.NotLoaded<association :source is not loaded>,
        translation_id: "fc80709a-39dc-4b9c-95c3-1d64ce818302",
        translation: #Ecto.Association.NotLoaded<association :translation is not loaded>,
        sheaf_id: nil,
        sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>,
        window: nil
      },
      inserted_at: ~U[2024-10-12 09:52:40Z],
      updated_at: ~U[2024-10-12 09:52:40Z]
    },
    %Vyasa.Sangh.Mark{
      __meta__: #Ecto.Schema.Metadata<:loaded, "marks">,
      id: "8af43833-575c-4eb8-83b1-eb4e58509e4c",
      body: nil,
      order: 4,
      state: :draft,
      verse_id: nil,
      sheaf_id: "7f4ab16b-0caf-4009-ba2a-3ddded81d9aa",
      sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>,
      binding_id: "23b70937-ed81-47fe-a560-ee14287bff7d",
      binding: %Vyasa.Adapters.Binding{
        __meta__: #Ecto.Schema.Metadata<:loaded, "bindings">,
        id: "23b70937-ed81-47fe-a560-ee14287bff7d",
        w_type: nil,
        field_key: ["target", "body_translit_meant"],
        node_id: nil,
        verse_id: nil,
        verse: #Ecto.Association.NotLoaded<association :verse is not loaded>,
        chapter_no: nil,
        chapter: #Ecto.Association.NotLoaded<association :chapter is not loaded>,
        source_id: nil,
        source: #Ecto.Association.NotLoaded<association :source is not loaded>,
        translation_id: "97a7a662-a91b-486f-93e8-7ae932d01a1a",
        translation: #Ecto.Association.NotLoaded<association :translation is not loaded>,
        sheaf_id: nil,
        sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>,
        window: nil
      },
      inserted_at: ~U[2024-10-12 09:46:13Z],
      updated_at: ~U[2024-10-12 09:46:13Z]
    },
    %Vyasa.Sangh.Mark{
      __meta__: #Ecto.Schema.Metadata<:loaded, "marks">,
      id: "c7ad47e6-629d-4382-936d-64d757772c4e",
      body: nil,
      order: 3,
      state: :draft,
      verse_id: nil,
      sheaf_id: "7f4ab16b-0caf-4009-ba2a-3ddded81d9aa",
      sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>,
      binding_id: "d5758230-7966-4f9b-8c16-ae13998cd71b",
      binding: %Vyasa.Adapters.Binding{
        __meta__: #Ecto.Schema.Metadata<:loaded, "bindings">,
        id: "d5758230-7966-4f9b-8c16-ae13998cd71b",
        w_type: nil,
        field_key: ["target", "body_translit_meant"],
        node_id: nil,
        verse_id: nil,
        verse: #Ecto.Association.NotLoaded<association :verse is not loaded>,
        chapter_no: nil,
        chapter: #Ecto.Association.NotLoaded<association :chapter is not loaded>,
        source_id: nil,
        source: #Ecto.Association.NotLoaded<association :source is not loaded>,
        translation_id: "fc80709a-39dc-4b9c-95c3-1d64ce818302",
        translation: #Ecto.Association.NotLoaded<association :translation is not loaded>,
        sheaf_id: nil,
        sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>,
        window: nil
      },
      inserted_at: ~U[2024-10-12 09:44:09Z],
      updated_at: ~U[2024-10-12 09:44:09Z]
    },
    %Vyasa.Sangh.Mark{
      __meta__: #Ecto.Schema.Metadata<:loaded, "marks">,
      id: "02218551-591f-4450-abbd-a7b7d76fd48e",
      body: "testing",
      order: 2,
      state: :live,
      verse_id: nil,
      sheaf_id: "7f4ab16b-0caf-4009-ba2a-3ddded81d9aa",
      sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>,
      binding_id: "19ffdc82-a5d8-49c3-8b01-1559736dad80",
      binding: %Vyasa.Adapters.Binding{
        __meta__: #Ecto.Schema.Metadata<:loaded, "bindings">,
        id: "19ffdc82-a5d8-49c3-8b01-1559736dad80",
        w_type: nil,
        field_key: ["target", "body_translit_meant"],
        node_id: nil,
        verse_id: nil,
        verse: #Ecto.Association.NotLoaded<association :verse is not loaded>,
        chapter_no: nil,
        chapter: #Ecto.Association.NotLoaded<association :chapter is not loaded>,
        source_id: nil,
        source: #Ecto.Association.NotLoaded<association :source is not loaded>,
        translation_id: "fc80709a-39dc-4b9c-95c3-1d64ce818302",
        translation: #Ecto.Association.NotLoaded<association :translation is not loaded>,
        sheaf_id: nil,
        sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>,
        window: nil
      },
      inserted_at: ~U[2024-10-12 09:43:19Z],
      updated_at: ~U[2024-10-12 09:43:19Z]
    },
    %Vyasa.Sangh.Mark{
      __meta__: #Ecto.Schema.Metadata<:loaded, "marks">,
      id: "90c6036a-9bd1-4b65-82d5-f121ec4d7867",
      body: nil,
      order: 2,
      state: :draft,
      verse_id: nil,
      sheaf_id: "7f4ab16b-0caf-4009-ba2a-3ddded81d9aa",
      sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>,
      binding_id: "b92f990d-99a2-4f04-a2d4-d1135021ee8c",
      binding: %Vyasa.Adapters.Binding{
        __meta__: #Ecto.Schema.Metadata<:loaded, "bindings">,
        id: "b92f990d-99a2-4f04-a2d4-d1135021ee8c",
        w_type: nil,
        field_key: ["target", "body_translit_meant"],
        node_id: nil,
        verse_id: nil,
        verse: #Ecto.Association.NotLoaded<association :verse is not loaded>,
        chapter_no: nil,
        chapter: #Ecto.Association.NotLoaded<association :chapter is not loaded>,
        source_id: nil,
        source: #Ecto.Association.NotLoaded<association :source is not loaded>,
        translation_id: "97a7a662-a91b-486f-93e8-7ae932d01a1a",
        translation: #Ecto.Association.NotLoaded<association :translation is not loaded>,
        sheaf_id: nil,
        sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>,
        window: nil
      },
      inserted_at: ~U[2024-10-11 09:03:00Z],
      updated_at: ~U[2024-10-11 09:03:00Z]
    }
  ],
  inserted_at: ~N[2024-09-27 00:51:48],
  updated_at: ~N[2024-09-27 00:51:48]
}
[debug] Replied in 81ms
[debug] HANDLE EVENT "verses::focus_toggle_on_quick_mark_drafting" in VyasaWeb.ModeLive.Mediator
  Component: VyasaWeb.Context.Read
  Parameters: %{"is_focusing?" => false, "value" => ""}
[debug] Replied in 129µs
iex([email protected])17>

* marks order force

* old man mark is not feeling so good

* ReWrite how marks get initialised @ :show_verse (#119)

* Minor change in fn signature

* Add init_draft_reflector()

---------

Co-authored-by: ks0m1c_dharma <[email protected]>

* Minor changes

* Add a generic modal wrapper (#120)

* Add generic debug dump component

This makes life easy when wiring things up

* Rename namespace for Context.Read.*

* Groundwork: add discuss component w sheafs

* Init Context.Components mod for common components

* Add skeletons for Sheaf Container

Container managers sheaf state within itself.
Should actually make the verse-matrix use this container, sometime.

* Minor changes, add some TODOs to share

explicit todos

Minor change

* Add live component EditableMarkDisplay

* Add UI improvements to EditableMarkDisplay

The edit button on quick draft should only be seen when the dropdown is
expanded and all the marks can be seen. The general pattern I'm trying
to follow is that buttons should only be shown when an action makes
sense. So here, if the user can't even see the marks currently
accumulating, then the user shouldn't have the chance to edit any marks.

Notice that the EditableMarkDisplay is a live_component that is a child
of a function component (collapsible_marks_display). This is so that it can keep its own state and
do it's own event-handling. I'm not sure if this is pattern-breaking.
A reference to the actual parent live_component that calls collapsible_marks_display
will always be there in case there's a need for the parent to handle
any particular events. So comms b/w live_components is still going to be
via phx-target values.

* Change <input/> -> <textarea/> fr quick_draft_form

* Add tailwind config for custom svg icons

not sure how the scaling for this works, seems like i can't just put in
the class="h-5 w-5" to do the scaling

* Let custom svg be scalable

* Subtly shift the ping indicator to control panel

* Marks ordering in Sheaf and L-Trees  (#114)

* do sheafs grow on trees

* sangh session dealing with lineage

* Solve initial order problem

* fix: ensure non-null id used @ EditableMarkDisplay

---------

Co-authored-by: ks0m1c_dharma <[email protected]>

* Trigger Diff

* TOMBSTONING

* Fix bugs and revert ui for read_mode:delete marks

1.  JIT generate id for marks yet to be inserted to the db: instead of
    using a temp id, I'm actually assigning a JIT-generated id for a
    mark even if that isn't inserted into the db yet. this has two
    benefits: div ids have meaningful static ids (e.g.
    mark-container-\<\> mark.id) regardless of whether that mark has
    been inserted into the db or not. While doing this, the changeset
    for marks has been udpated to add id as well. This fixes a bunch of
    id-based errors as well.

2.  while doing 1, it came to light that the bindHoverune handlers were
    not handling the draft mark update properly (i.e. not using the
    already existing update function in mark) . it's changed now,
    example of the diff:

    ``` diff
      @impl true
      def handle_event(
            "bindHoveRune",
            %{"binding" => bind = %{"verse_id" => verse_id}},
            %{
              assigns: %{
                kv_verses: verses,
                marks: [%Mark{state: :draft, verse_id: curr_verse_id} = d_mark | marks]
              }
            } = socket
          )
          when is_binary(curr_verse_id) and verse_id != curr_verse_id do
        # binding here blocks the stream from appending to quote
        bind = Draft.bind_node(bind)

        bound_verses =
          verses
           |> then(&put_in(&1[verse_id].binding, bind))
           |> then(&put_in(&1[curr_verse_id].binding, nil))

    +    updated_draft_mark = d_mark |> Mark.update_mark(%{binding: bind, verse_id: verse_id})
    +
         {:noreply,
          socket
          |> mutate_verses(curr_verse_id, bound_verses)
          |> mutate_verses(verse_id, bound_verses)
    -     |> assign(:marks, [%{d_mark | binding: bind, verse_id: verse_id} | marks])}
    +     |> assign(:marks, [updated_draft_mark | marks])}
       end
    ```

3.  add ui state structs: all of the relevant ui states have structs
    that are intended to be static interfaces. this felt better than
    directly keeping state within various sockets and is done with a
    view to remove live components and change them to function
    components wherever possible.

4.  bugfix for `order()`:

    - it had an off-by-one-error
    - shifted it to Vyasa.Sangh.Mark
    - also note that the order shall be 1-indexed instead of 0-indexed
      for human-friendliness

5.  minor fixes:

    1.  fix update<sub>mark</sub> default argument

        ``` diff
        -def update_mark(%Mark{} = draft_mark, opts \\ []) do
        +def update_mark(%Mark{} = draft_mark, opts \\ %{}) do
        ```

1.  In this commit, the marks<sub>ui</sub> is NOT kept by the read
    context module, that's why when I update things by create mark or
    delete mark, the ui state is not preserved and initial, default
    state is seen. This was intentionally done in this commit because
    I'm having problems with duplicate ids for verses for some reason,
    I'll show it in the next commit, so that the problem can be clearly
    seen.

* [BUGGY] keep marks_ui within ReadContext

This is buggy, not sure why there's a duplicate yet.  will come back to
it after lunch

Replication Steps:
1. delete all marks and see there's no error
2. create first mark ==> no error
3. create second mark ==> crashes due to duplicate verse id

Crash dump:

[debug] Replied in 13ms
[error] GenServer #PID<0.8416.0> terminating
** (RuntimeError) found duplicate ID "verse-7d9d588a-34fc-4f19-b974-fc32b49b6a61" for component VyasaWeb.Context.Read.VerseMatrix when rendering template
    (phoenix_live_view 1.0.0-rc.6) lib/phoenix_live_view/diff.ex:634: anonymous fn/5 in Phoenix.LiveView.Diff.render_pending_components/6
    (elixir 1.17.2) lib/enum.ex:2531: Enum."-reduce/3-lists^foldl/2-0-"/3
    (phoenix_live_view 1.0.0-rc.6) lib/phoenix_live_view/diff.ex:631: anonymous fn/4 in Phoenix.LiveView.Diff.render_pending_components/6
    (stdlib 5.2.3) maps.erl:416: :maps.fold_1/4
    (phoenix_live_view 1.0.0-rc.6) lib/phoenix_live_view/diff.ex:625: Phoenix.LiveView.Diff.render_pending_components/6
    (phoenix_live_view 1.0.0-rc.6) lib/phoenix_live_view/diff.ex:217: Phoenix.LiveView.Diff.write_component/4
    (phoenix_live_view 1.0.0-rc.6) lib/phoenix_live_view/channel.ex:662: Phoenix.LiveView.Channel.component_handle/4
    (stdlib 5.2.3) gen_server.erl:1095: :gen_server.try_handle_info/3
    (stdlib 5.2.3) gen_server.erl:1183: :gen_server.handle_msg/6
    (stdlib 5.2.3) proc_lib.erl:251: :proc_lib.wake_up/3
Last message: %Phoenix.Socket.Message{topic: "lv:phx-F_1MH_6F0ciqVqwi", event: "event", payload: %{"cid" => 3, "event" => "createMark", "type" => "form", "value" => "body=how+about+now%2C+any+duplicate%3F"}, ref: "23", join_ref: "4"}
State: %{socket: #Phoenix.LiveView.Socket<id: "phx-F_1MH_6F0ciqVqwi", endpoint: VyasaWeb.Endpoint, view: VyasaWeb.ModeLive.Mediator, parent_pid: nil, root_pid: #PID<0.8416.0>, router: VyasaWeb.Router, assigns: %{mode: %VyasaWeb.ModeLive.UserMode{mode: "read", default_ui_state: %VyasaWeb.ModeLive.UiState{show_media_bridge?: true, show_action_bar?: true}, mode_icon_name: "hero-book-open", quick_actions: [:mark_quote, :bookmark], control_panel_modes: ["discuss"], mode_actions: [:mark_quote, :bookmark], action_bar_actions: [:nav_back, :nav_fwd], action_bar_info_types: nil, action_bar_component: VyasaWeb.MediaLive.MediaBridge, action_bar_component_selector: "media-bridge", control_panel_component: VyasaWeb.ControlPanel, control_panel_component_selector: "control-panel", mode_context_component: VyasaWeb.Context.Read, mode_context_component_selector: "read"}, session: %VyasaWeb.Session{name: "ritesh kumar", id: "IhrQV0ypqg8bHakbvb2bymNF", active: true, sangh: %Vyasa.Sangh.Session{__meta__: #Ecto.Schema.Metadata<:loaded, "sessions">, id: "164eb05d-221a-4939-b180-8394e1a5515f", sheafs: #Ecto.Association.NotLoaded<association :sheafs is not loaded>, inserted_at: ~U[2024-09-27 00:51:48Z], updated_at: ~U[2024-09-27 00:51:48Z]}, last_opened: "2024-09-23T11:03:32.022987Z"}, __changed__: %{}, flash: %{}, locale: "en-GB", url_params: %{"chap_no" => "1", "source_title" => "hanuman_chalisa"}, live_action: :show_verses, ui_state: %VyasaWeb.ModeLive.UiState{show_media_bridge?: true, show_action_bar?: true}, device_type: :desktop, tz: %{timezone: "Asia/Singapore", timezone_offset: 480}}, transport_pid: #PID<0.8403.0>, ...>, components: {%{15 => {VyasaWeb.Context.Read.VerseMatrix, "verse-aa3ad88b-0de1-443e-b471-c08a44e67c61", %{id: "verse-aa3ad88b-0de1-443e-b471-c08a44e67c61", edge: [%{title: "1.10", field: [:body], verseup: {:big, "dn"}}, %{node: %Vyasa.Written.Translation{__meta__: #Ecto.Schema.Metadata<:loaded, "translations">, id: "651676b6-ffc3-41c1-b525-f376989f639e", lang: "en", type: "verses", target: %Vyasa.Written.Translation.Target{id: "dd20a94f-8f34-49f8-8da8-4321cfecf172", title: nil, title_translit: nil, body: "प्रभु चरित्र सुनिबे को रसिया ।\n\nराम लखन सीता मन बसिया ॥८॥", body_meant: nil, body_translit: "prabhu caritra sunibe ko rasiyā .\n\nrāma lakhana sītā mana basiyā ..8..", body_translit_meant: "You feel extremely delighted in listening to Lord Rama’s doings and conduct. Lord Rama, Mother Sita, and Lord Laxmana dwell forever in your heart."}, verse_id: "aa3ad88b-0de1-443e-b471-c08a44e67c61", verse: #Ecto.Association.NotLoaded<association :verse is not loaded>, chapter_no: nil, chapter: #Ecto.Association.NotLoaded<association :chapter is not loaded>, source_id: "63918acd-77a9-451a-b8d1-8d5b73208eae", source: #Ecto.Association.NotLoaded<association :source is not loaded>}, field: [:target, :body_translit], verseup: :mid}, %{node: %Vyasa.Written.Translation{__meta__: #Ecto.Schema.Metadata<:loaded, "translations">, id: "651676b6-ffc3-41c1-b525-f376989f639e", lang: "en", type: "verses", target: %Vyasa.Written.Translation.Target{id: "dd20a94f-8f34-49f8-8da8-4321cfecf172", title: nil, title_translit: nil, body: "प्रभु चरित्र सुनिबे को रसिया ।\n\nराम लखन सीता मन बसिया ॥८॥", body_meant: nil, body_translit: "prabhu caritra sunibe ko rasiyā .\n\nrāma lakhana sītā mana basiyā ..8..", body_translit_meant: "You feel extremely delighted in listening to Lord Rama’s doings and conduct. Lord Rama, Mother Sita, and Lord Laxmana dwell forever in your heart."}, verse_id: "aa3ad88b-0de1-443e-b471-c08a44e67c61", verse: #Ecto.Association.NotLoaded<association :verse is not loaded>, chapter_no: nil, chapter: #Ecto.Association.NotLoaded<association :chapter is not loaded>, source_id: "63918acd-77a9-451a-b8d1-8d5b73208eae", source: #Ecto.Association.NotLoaded<association :source is not loaded>}, field: [:target, :body_translit_meant], verseup: :mid}, %{node: %Vyasa.Written.Translation{__meta__: #Ecto.Schema.Metadata<:loaded, "translations">, id: "651676b6-ffc3-41c1-b525-f376989f639e", lang: "en", type: "verses", target: %Vyasa.Written.Translation.Target{id: "dd20a94f-8f34-49f8-8da8-4321cfecf172", title: nil, title_translit: nil, body: "प्रभु चरित्र सुनिबे को रसिया ।\n\nराम लखन सीता मन बसिया ॥८॥", body_meant: nil, body_translit: "prabhu caritra sunibe ko rasiyā .\n\nrāma lakhana sītā mana basiyā ..8..", body_translit_meant: "You feel extremely delighted in listening to Lord Rama’s doings and conduct. Lord Rama, Mother Sita, and Lord Laxmana dwell forever in your heart."}, verse_id: "aa3ad88b-0de1-443e-b471-c08a44e67c61", verse: #Ecto.Association.NotLoaded<association :verse is not loaded>, chapter_no: nil, chapter: #Ecto.Association.NotLoaded<association :chapter is not loaded>, source_id: "63918acd-77a9-451a-b8d1-8d5b73208eae", source: #Ecto.Association.NotLoaded<association :source is not loaded>}, field: [:target, :body], verseup: :mid}], __changed__: %{}, flash: %{}, marks: [%Vyasa.Sangh.Mark{__meta__: #Ecto.Schema.Metadata<:loaded, "marks">, id: "5dfdb167-6c57-46dd-a0c4-10b52cb03a85", body: "wonderful", order: 2, state: :live, verse_id: nil, sheaf_id: "7f4ab16b-0caf-4009-ba2a-3ddded81d9aa", sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>, binding_id: "001da594-3808-46cf-9b9c-5dfb3559780e", binding: %Vyasa.Adapters.Binding{__meta__: #Ecto.Schema.Metadata<:loaded, "bindings">, id: "001da594-3808-46cf-9b9c-5dfb3559780e", w_type: nil, field_key: ["target", "body_translit_meant"], node_id: nil, verse_id: nil, verse: #Ecto.Association.NotLoaded<association :verse is not loaded>, chapter_no: nil, chapter: #Ecto.Association.NotLoaded<association :chapter is not loaded>, source_id: nil, source: #Ecto.Association.NotLoaded<association :source is not loaded>, translation_id: "97a7a662-a91b-486f-93e8-7ae932d01a1a", translation: #Ecto.Association.NotLoaded<association :translation is not loaded>, sheaf_id: nil, sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>, window: nil}, inserted_at: ~U[2024-10-11 04:31:50Z], updated_at: ~U[2024-10-11 04:31:50Z]}, %Vyasa.Sangh.Mark{__meta__: #Ecto.Schema.Metadata<:loaded, "marks">, id: "273a093d-4f90-40a4-b19a-2f8f7825d201", body: "truncated utc datetime", order: 1, state: :live, verse_id: nil, sheaf_id: "7f4ab16b-0caf-4009-ba2a-3ddded81d9aa", sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>, binding_id: "ef39315b-530c-4841-ba32-86773f451727", binding: %Vyasa.Adapt (truncated)
[debug] MOUNT VyasaWeb.ModeLive.Mediator
  Parameters: %{"chap_no" => "1", "source_title" => "hanuman_chalisa"}
  Session: %{"_csrf_token" => "DJ-RIoXwEzHW82rbb21le_8k"}
[debug] QUERY OK source="sessions" db=3.5ms idle=1690.4ms
SELECT s0."id", s0."inserted_at", s0."updated_at" FROM "sessions" AS s0 WHERE (s0."id" = $1) ["164eb05d-221a-4939-b180-8394e1a5515f"]
↳

* Fix duplicate id issue on verse matrix

* Standardise use of @event_target, cleanups

When using @event_target, the intent is that phx-target values
will be passed around. This must be agnostic to the 2 main ways of
supplying that argument, as a HTML selector, or as a module name (or @myself).
Therefore, we should discourage ourselves from doing format-strings at
the point of the @event_target being supplied as an argument, meaning:

good, because agnostic:
phx-target={@event_target}

bad, because hardcoded:
phx-target={"#" <> @event_target}
* in this case, the event trigger will th…
* Add generic debug dump component

This makes life easy when wiring things up

* Rename namespace for Context.Read.*

* Groundwork: add discuss component w sheafs

* Init Context.Components mod for common components

* Add skeletons for Sheaf Container

Container managers sheaf state within itself.
Should actually make the verse-matrix use this container, sometime.

* Minor changes, add some TODOs to share

explicit todos

Minor change

* Add live component EditableMarkDisplay

* Add UI improvements to EditableMarkDisplay

The edit button on quick draft should only be seen when the dropdown is
expanded and all the marks can be seen. The general pattern I'm trying
to follow is that buttons should only be shown when an action makes
sense. So here, if the user can't even see the marks currently
accumulating, then the user shouldn't have the chance to edit any marks.

Notice that the EditableMarkDisplay is a live_component that is a child
of a function component (collapsible_marks_display). This is so that it can keep its own state and
do it's own event-handling. I'm not sure if this is pattern-breaking.
A reference to the actual parent live_component that calls collapsible_marks_display
will always be there in case there's a need for the parent to handle
any particular events. So comms b/w live_components is still going to be
via phx-target values.

* Change <input/> -> <textarea/> fr quick_draft_form

* Add tailwind config for custom svg icons

not sure how the scaling for this works, seems like i can't just put in
the class="h-5 w-5" to do the scaling

* Let custom svg be scalable

* Subtly shift the ping indicator to control panel

* Marks ordering in Sheaf and L-Trees  (#114)

* do sheafs grow on trees

* sangh session dealing with lineage

* Solve initial order problem

* fix: ensure non-null id used @ EditableMarkDisplay

---------

Co-authored-by: ks0m1c_dharma <[email protected]>

* Trigger Diff

* TOMBSTONING

* Fix bugs and revert ui for read_mode:delete marks

1.  JIT generate id for marks yet to be inserted to the db: instead of
    using a temp id, I'm actually assigning a JIT-generated id for a
    mark even if that isn't inserted into the db yet. this has two
    benefits: div ids have meaningful static ids (e.g.
    mark-container-\<\> mark.id) regardless of whether that mark has
    been inserted into the db or not. While doing this, the changeset
    for marks has been udpated to add id as well. This fixes a bunch of
    id-based errors as well.

2.  while doing 1, it came to light that the bindHoverune handlers were
    not handling the draft mark update properly (i.e. not using the
    already existing update function in mark) . it's changed now,
    example of the diff:

    ``` diff
      @impl true
      def handle_event(
            "bindHoveRune",
            %{"binding" => bind = %{"verse_id" => verse_id}},
            %{
              assigns: %{
                kv_verses: verses,
                marks: [%Mark{state: :draft, verse_id: curr_verse_id} = d_mark | marks]
              }
            } = socket
          )
          when is_binary(curr_verse_id) and verse_id != curr_verse_id do
        # binding here blocks the stream from appending to quote
        bind = Draft.bind_node(bind)

        bound_verses =
          verses
           |> then(&put_in(&1[verse_id].binding, bind))
           |> then(&put_in(&1[curr_verse_id].binding, nil))

    +    updated_draft_mark = d_mark |> Mark.update_mark(%{binding: bind, verse_id: verse_id})
    +
         {:noreply,
          socket
          |> mutate_verses(curr_verse_id, bound_verses)
          |> mutate_verses(verse_id, bound_verses)
    -     |> assign(:marks, [%{d_mark | binding: bind, verse_id: verse_id} | marks])}
    +     |> assign(:marks, [updated_draft_mark | marks])}
       end
    ```

3.  add ui state structs: all of the relevant ui states have structs
    that are intended to be static interfaces. this felt better than
    directly keeping state within various sockets and is done with a
    view to remove live components and change them to function
    components wherever possible.

4.  bugfix for `order()`:

    - it had an off-by-one-error
    - shifted it to Vyasa.Sangh.Mark
    - also note that the order shall be 1-indexed instead of 0-indexed
      for human-friendliness

5.  minor fixes:

    1.  fix update<sub>mark</sub> default argument

        ``` diff
        -def update_mark(%Mark{} = draft_mark, opts \\ []) do
        +def update_mark(%Mark{} = draft_mark, opts \\ %{}) do
        ```

1.  In this commit, the marks<sub>ui</sub> is NOT kept by the read
    context module, that's why when I update things by create mark or
    delete mark, the ui state is not preserved and initial, default
    state is seen. This was intentionally done in this commit because
    I'm having problems with duplicate ids for verses for some reason,
    I'll show it in the next commit, so that the problem can be clearly
    seen.

* [BUGGY] keep marks_ui within ReadContext

This is buggy, not sure why there's a duplicate yet.  will come back to
it after lunch

Replication Steps:
1. delete all marks and see there's no error
2. create first mark ==> no error
3. create second mark ==> crashes due to duplicate verse id

Crash dump:

[debug] Replied in 13ms
[error] GenServer #PID<0.8416.0> terminating
** (RuntimeError) found duplicate ID "verse-7d9d588a-34fc-4f19-b974-fc32b49b6a61" for component VyasaWeb.Context.Read.VerseMatrix when rendering template
    (phoenix_live_view 1.0.0-rc.6) lib/phoenix_live_view/diff.ex:634: anonymous fn/5 in Phoenix.LiveView.Diff.render_pending_components/6
    (elixir 1.17.2) lib/enum.ex:2531: Enum."-reduce/3-lists^foldl/2-0-"/3
    (phoenix_live_view 1.0.0-rc.6) lib/phoenix_live_view/diff.ex:631: anonymous fn/4 in Phoenix.LiveView.Diff.render_pending_components/6
    (stdlib 5.2.3) maps.erl:416: :maps.fold_1/4
    (phoenix_live_view 1.0.0-rc.6) lib/phoenix_live_view/diff.ex:625: Phoenix.LiveView.Diff.render_pending_components/6
    (phoenix_live_view 1.0.0-rc.6) lib/phoenix_live_view/diff.ex:217: Phoenix.LiveView.Diff.write_component/4
    (phoenix_live_view 1.0.0-rc.6) lib/phoenix_live_view/channel.ex:662: Phoenix.LiveView.Channel.component_handle/4
    (stdlib 5.2.3) gen_server.erl:1095: :gen_server.try_handle_info/3
    (stdlib 5.2.3) gen_server.erl:1183: :gen_server.handle_msg/6
    (stdlib 5.2.3) proc_lib.erl:251: :proc_lib.wake_up/3
Last message: %Phoenix.Socket.Message{topic: "lv:phx-F_1MH_6F0ciqVqwi", event: "event", payload: %{"cid" => 3, "event" => "createMark", "type" => "form", "value" => "body=how+about+now%2C+any+duplicate%3F"}, ref: "23", join_ref: "4"}
State: %{socket: #Phoenix.LiveView.Socket<id: "phx-F_1MH_6F0ciqVqwi", endpoint: VyasaWeb.Endpoint, view: VyasaWeb.ModeLive.Mediator, parent_pid: nil, root_pid: #PID<0.8416.0>, router: VyasaWeb.Router, assigns: %{mode: %VyasaWeb.ModeLive.UserMode{mode: "read", default_ui_state: %VyasaWeb.ModeLive.UiState{show_media_bridge?: true, show_action_bar?: true}, mode_icon_name: "hero-book-open", quick_actions: [:mark_quote, :bookmark], control_panel_modes: ["discuss"], mode_actions: [:mark_quote, :bookmark], action_bar_actions: [:nav_back, :nav_fwd], action_bar_info_types: nil, action_bar_component: VyasaWeb.MediaLive.MediaBridge, action_bar_component_selector: "media-bridge", control_panel_component: VyasaWeb.ControlPanel, control_panel_component_selector: "control-panel", mode_context_component: VyasaWeb.Context.Read, mode_context_component_selector: "read"}, session: %VyasaWeb.Session{name: "ritesh kumar", id: "IhrQV0ypqg8bHakbvb2bymNF", active: true, sangh: %Vyasa.Sangh.Session{__meta__: #Ecto.Schema.Metadata<:loaded, "sessions">, id: "164eb05d-221a-4939-b180-8394e1a5515f", sheafs: #Ecto.Association.NotLoaded<association :sheafs is not loaded>, inserted_at: ~U[2024-09-27 00:51:48Z], updated_at: ~U[2024-09-27 00:51:48Z]}, last_opened: "2024-09-23T11:03:32.022987Z"}, __changed__: %{}, flash: %{}, locale: "en-GB", url_params: %{"chap_no" => "1", "source_title" => "hanuman_chalisa"}, live_action: :show_verses, ui_state: %VyasaWeb.ModeLive.UiState{show_media_bridge?: true, show_action_bar?: true}, device_type: :desktop, tz: %{timezone: "Asia/Singapore", timezone_offset: 480}}, transport_pid: #PID<0.8403.0>, ...>, components: {%{15 => {VyasaWeb.Context.Read.VerseMatrix, "verse-aa3ad88b-0de1-443e-b471-c08a44e67c61", %{id: "verse-aa3ad88b-0de1-443e-b471-c08a44e67c61", edge: [%{title: "1.10", field: [:body], verseup: {:big, "dn"}}, %{node: %Vyasa.Written.Translation{__meta__: #Ecto.Schema.Metadata<:loaded, "translations">, id: "651676b6-ffc3-41c1-b525-f376989f639e", lang: "en", type: "verses", target: %Vyasa.Written.Translation.Target{id: "dd20a94f-8f34-49f8-8da8-4321cfecf172", title: nil, title_translit: nil, body: "प्रभु चरित्र सुनिबे को रसिया ।\n\nराम लखन सीता मन बसिया ॥८॥", body_meant: nil, body_translit: "prabhu caritra sunibe ko rasiyā .\n\nrāma lakhana sītā mana basiyā ..8..", body_translit_meant: "You feel extremely delighted in listening to Lord Rama’s doings and conduct. Lord Rama, Mother Sita, and Lord Laxmana dwell forever in your heart."}, verse_id: "aa3ad88b-0de1-443e-b471-c08a44e67c61", verse: #Ecto.Association.NotLoaded<association :verse is not loaded>, chapter_no: nil, chapter: #Ecto.Association.NotLoaded<association :chapter is not loaded>, source_id: "63918acd-77a9-451a-b8d1-8d5b73208eae", source: #Ecto.Association.NotLoaded<association :source is not loaded>}, field: [:target, :body_translit], verseup: :mid}, %{node: %Vyasa.Written.Translation{__meta__: #Ecto.Schema.Metadata<:loaded, "translations">, id: "651676b6-ffc3-41c1-b525-f376989f639e", lang: "en", type: "verses", target: %Vyasa.Written.Translation.Target{id: "dd20a94f-8f34-49f8-8da8-4321cfecf172", title: nil, title_translit: nil, body: "प्रभु चरित्र सुनिबे को रसिया ।\n\nराम लखन सीता मन बसिया ॥८॥", body_meant: nil, body_translit: "prabhu caritra sunibe ko rasiyā .\n\nrāma lakhana sītā mana basiyā ..8..", body_translit_meant: "You feel extremely delighted in listening to Lord Rama’s doings and conduct. Lord Rama, Mother Sita, and Lord Laxmana dwell forever in your heart."}, verse_id: "aa3ad88b-0de1-443e-b471-c08a44e67c61", verse: #Ecto.Association.NotLoaded<association :verse is not loaded>, chapter_no: nil, chapter: #Ecto.Association.NotLoaded<association :chapter is not loaded>, source_id: "63918acd-77a9-451a-b8d1-8d5b73208eae", source: #Ecto.Association.NotLoaded<association :source is not loaded>}, field: [:target, :body_translit_meant], verseup: :mid}, %{node: %Vyasa.Written.Translation{__meta__: #Ecto.Schema.Metadata<:loaded, "translations">, id: "651676b6-ffc3-41c1-b525-f376989f639e", lang: "en", type: "verses", target: %Vyasa.Written.Translation.Target{id: "dd20a94f-8f34-49f8-8da8-4321cfecf172", title: nil, title_translit: nil, body: "प्रभु चरित्र सुनिबे को रसिया ।\n\nराम लखन सीता मन बसिया ॥८॥", body_meant: nil, body_translit: "prabhu caritra sunibe ko rasiyā .\n\nrāma lakhana sītā mana basiyā ..8..", body_translit_meant: "You feel extremely delighted in listening to Lord Rama’s doings and conduct. Lord Rama, Mother Sita, and Lord Laxmana dwell forever in your heart."}, verse_id: "aa3ad88b-0de1-443e-b471-c08a44e67c61", verse: #Ecto.Association.NotLoaded<association :verse is not loaded>, chapter_no: nil, chapter: #Ecto.Association.NotLoaded<association :chapter is not loaded>, source_id: "63918acd-77a9-451a-b8d1-8d5b73208eae", source: #Ecto.Association.NotLoaded<association :source is not loaded>}, field: [:target, :body], verseup: :mid}], __changed__: %{}, flash: %{}, marks: [%Vyasa.Sangh.Mark{__meta__: #Ecto.Schema.Metadata<:loaded, "marks">, id: "5dfdb167-6c57-46dd-a0c4-10b52cb03a85", body: "wonderful", order: 2, state: :live, verse_id: nil, sheaf_id: "7f4ab16b-0caf-4009-ba2a-3ddded81d9aa", sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>, binding_id: "001da594-3808-46cf-9b9c-5dfb3559780e", binding: %Vyasa.Adapters.Binding{__meta__: #Ecto.Schema.Metadata<:loaded, "bindings">, id: "001da594-3808-46cf-9b9c-5dfb3559780e", w_type: nil, field_key: ["target", "body_translit_meant"], node_id: nil, verse_id: nil, verse: #Ecto.Association.NotLoaded<association :verse is not loaded>, chapter_no: nil, chapter: #Ecto.Association.NotLoaded<association :chapter is not loaded>, source_id: nil, source: #Ecto.Association.NotLoaded<association :source is not loaded>, translation_id: "97a7a662-a91b-486f-93e8-7ae932d01a1a", translation: #Ecto.Association.NotLoaded<association :translation is not loaded>, sheaf_id: nil, sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>, window: nil}, inserted_at: ~U[2024-10-11 04:31:50Z], updated_at: ~U[2024-10-11 04:31:50Z]}, %Vyasa.Sangh.Mark{__meta__: #Ecto.Schema.Metadata<:loaded, "marks">, id: "273a093d-4f90-40a4-b19a-2f8f7825d201", body: "truncated utc datetime", order: 1, state: :live, verse_id: nil, sheaf_id: "7f4ab16b-0caf-4009-ba2a-3ddded81d9aa", sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>, binding_id: "ef39315b-530c-4841-ba32-86773f451727", binding: %Vyasa.Adapt (truncated)
[debug] MOUNT VyasaWeb.ModeLive.Mediator
  Parameters: %{"chap_no" => "1", "source_title" => "hanuman_chalisa"}
  Session: %{"_csrf_token" => "DJ-RIoXwEzHW82rbb21le_8k"}
[debug] QUERY OK source="sessions" db=3.5ms idle=1690.4ms
SELECT s0."id", s0."inserted_at", s0."updated_at" FROM "sessions" AS s0 WHERE (s0."id" = $1) ["164eb05d-221a-4939-b180-8394e1a5515f"]
↳

* Fix duplicate id issue on verse matrix

* Standardise use of @event_target, cleanups

When using @event_target, the intent is that phx-target values
will be passed around. This must be agnostic to the 2 main ways of
supplying that argument, as a HTML selector, or as a module name (or @myself).
Therefore, we should discourage ourselves from doing format-strings at
the point of the @event_target being supplied as an argument, meaning:

good, because agnostic:
phx-target={@event_target}

bad, because hardcoded:
phx-target={"#" <> @event_target}
* in this case, the event trigger will throw a dom error.

* [Attempt]: Sanitise, defrag orders in marks-list

If this is an anti-pattern, then this commit should be reverted.

* UI fixes: hide buttons on marks when !is_editable?

* Add in stub event handlers to prevent crashes

Temporary stuff, will be addressed in immediate-next PR

* Minor changes

* Toggle edit state for marks content

* Partial implementation of edit marks

the form stuff doesn't exist so it's not wired up yet. To be frank,
im' not sure how to set up a form without it needing to hold state.

* [BUGGY] Wire up form update for edit

this does the following:
1. wires up the form like how we usedd it in createMark
2. actually captures the event properly within the event handler,
everything looks good at that point, even the edit_mark_in_marks
function on inspection looks good
3. the marks is getting assigned to properly because the newly edited
mark content is seen after doing a dom refresh
4. HOWEVER, the print statement at the sheaf_update function DOES NOT
show the correct, updated marks in the sheaf

here's a dump for it for reference

[debug] HANDLE EVENT "editMarkContent" in VyasaWeb.ModeLive.Mediator
  Component: VyasaWeb.Context.Read
  Parameters: %{"mark_id" => "02218551-591f-4450-abbd-a7b7d76fd48e"}
[debug] Replied in 2ms
[debug] HANDLE EVENT "editMarkContent" in VyasaWeb.ModeLive.Mediator
  Component: VyasaWeb.Context.Read
  Parameters: %{"mark_body" => "  testing\n\n\nwhat hte heck", "mark_id" => "02218551-591f-4450-abbd-a7b7d76fd48e"}
>>> UPDATE SHEAF -- SHOULD BE WRITING TO DB NOW: %Vyasa.Sangh.Sheaf{
  __meta__: #Ecto.Schema.Metadata<:loaded, "sheafs">,
  id: "7f4ab16b-0caf-4009-ba2a-3ddded81d9aa",
  body: nil,
  active: true,
  path: %EctoLtree.LabelTree{labels: ["7f4ab16b"]},
  signature: nil,
  traits: ["draft"],
  child_count: 0,
  session_id: "164eb05d-221a-4939-b180-8394e1a5515f",
  session: #Ecto.Association.NotLoaded<association :session is not loaded>,
  parent_id: nil,
  parent: #Ecto.Association.NotLoaded<association :parent is not loaded>,
  marks: [
    %Vyasa.Sangh.Mark{
      __meta__: #Ecto.Schema.Metadata<:loaded, "marks">,
      id: "555eb625-e392-496e-9831-4f4c130be6fd",
      body: "wonderful stuff",
      order: 5,
      state: :live,
      verse_id: nil,
      sheaf_id: "7f4ab16b-0caf-4009-ba2a-3ddded81d9aa",
      sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>,
      binding_id: "072124d0-5e27-4601-832f-35eaa6426879",
      binding: %Vyasa.Adapters.Binding{
        __meta__: #Ecto.Schema.Metadata<:loaded, "bindings">,
        id: "072124d0-5e27-4601-832f-35eaa6426879",
        w_type: nil,
        field_key: ["target", "body_translit_meant"],
        node_id: nil,
        verse_id: nil,
        verse: #Ecto.Association.NotLoaded<association :verse is not loaded>,
        chapter_no: nil,
        chapter: #Ecto.Association.NotLoaded<association :chapter is not loaded>,
        source_id: nil,
        source: #Ecto.Association.NotLoaded<association :source is not loaded>,
        translation_id: "97a7a662-a91b-486f-93e8-7ae932d01a1a",
        translation: #Ecto.Association.NotLoaded<association :translation is not loaded>,
        sheaf_id: nil,
        sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>,
        window: nil
      },
      inserted_at: ~U[2024-10-12 08:46:54Z],
      updated_at: ~U[2024-10-12 08:46:54Z]
    },
    %Vyasa.Sangh.Mark{
      __meta__: #Ecto.Schema.Metadata<:loaded, "marks">,
      id: "b22a5661-8268-4875-be26-a12256414136",
      body: nil,
      order: 5,
      state: :draft,
      verse_id: nil,
      sheaf_id: "7f4ab16b-0caf-4009-ba2a-3ddded81d9aa",
      sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>,
      binding_id: "90e18044-73b2-4ede-a149-a381de893b9f",
      binding: %Vyasa.Adapters.Binding{
        __meta__: #Ecto.Schema.Metadata<:loaded, "bindings">,
        id: "90e18044-73b2-4ede-a149-a381de893b9f",
        w_type: nil,
        field_key: ["target", "body_translit_meant"],
        node_id: nil,
        verse_id: nil,
        verse: #Ecto.Association.NotLoaded<association :verse is not loaded>,
        chapter_no: nil,
        chapter: #Ecto.Association.NotLoaded<association :chapter is not loaded>,
        source_id: nil,
        source: #Ecto.Association.NotLoaded<association :source is not loaded>,
        translation_id: "fc80709a-39dc-4b9c-95c3-1d64ce818302",
        translation: #Ecto.Association.NotLoaded<association :translation is not loaded>,
        sheaf_id: nil,
        sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>,
        window: nil
      },
      inserted_at: ~U[2024-10-12 09:52:40Z],
      updated_at: ~U[2024-10-12 09:52:40Z]
    },
    %Vyasa.Sangh.Mark{
      __meta__: #Ecto.Schema.Metadata<:loaded, "marks">,
      id: "8af43833-575c-4eb8-83b1-eb4e58509e4c",
      body: nil,
      order: 4,
      state: :draft,
      verse_id: nil,
      sheaf_id: "7f4ab16b-0caf-4009-ba2a-3ddded81d9aa",
      sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>,
      binding_id: "23b70937-ed81-47fe-a560-ee14287bff7d",
      binding: %Vyasa.Adapters.Binding{
        __meta__: #Ecto.Schema.Metadata<:loaded, "bindings">,
        id: "23b70937-ed81-47fe-a560-ee14287bff7d",
        w_type: nil,
        field_key: ["target", "body_translit_meant"],
        node_id: nil,
        verse_id: nil,
        verse: #Ecto.Association.NotLoaded<association :verse is not loaded>,
        chapter_no: nil,
        chapter: #Ecto.Association.NotLoaded<association :chapter is not loaded>,
        source_id: nil,
        source: #Ecto.Association.NotLoaded<association :source is not loaded>,
        translation_id: "97a7a662-a91b-486f-93e8-7ae932d01a1a",
        translation: #Ecto.Association.NotLoaded<association :translation is not loaded>,
        sheaf_id: nil,
        sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>,
        window: nil
      },
      inserted_at: ~U[2024-10-12 09:46:13Z],
      updated_at: ~U[2024-10-12 09:46:13Z]
    },
    %Vyasa.Sangh.Mark{
      __meta__: #Ecto.Schema.Metadata<:loaded, "marks">,
      id: "c7ad47e6-629d-4382-936d-64d757772c4e",
      body: nil,
      order: 3,
      state: :draft,
      verse_id: nil,
      sheaf_id: "7f4ab16b-0caf-4009-ba2a-3ddded81d9aa",
      sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>,
      binding_id: "d5758230-7966-4f9b-8c16-ae13998cd71b",
      binding: %Vyasa.Adapters.Binding{
        __meta__: #Ecto.Schema.Metadata<:loaded, "bindings">,
        id: "d5758230-7966-4f9b-8c16-ae13998cd71b",
        w_type: nil,
        field_key: ["target", "body_translit_meant"],
        node_id: nil,
        verse_id: nil,
        verse: #Ecto.Association.NotLoaded<association :verse is not loaded>,
        chapter_no: nil,
        chapter: #Ecto.Association.NotLoaded<association :chapter is not loaded>,
        source_id: nil,
        source: #Ecto.Association.NotLoaded<association :source is not loaded>,
        translation_id: "fc80709a-39dc-4b9c-95c3-1d64ce818302",
        translation: #Ecto.Association.NotLoaded<association :translation is not loaded>,
        sheaf_id: nil,
        sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>,
        window: nil
      },
      inserted_at: ~U[2024-10-12 09:44:09Z],
      updated_at: ~U[2024-10-12 09:44:09Z]
    },
    %Vyasa.Sangh.Mark{
      __meta__: #Ecto.Schema.Metadata<:loaded, "marks">,
      id: "02218551-591f-4450-abbd-a7b7d76fd48e",
      body: "testing",
      order: 2,
      state: :live,
      verse_id: nil,
      sheaf_id: "7f4ab16b-0caf-4009-ba2a-3ddded81d9aa",
      sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>,
      binding_id: "19ffdc82-a5d8-49c3-8b01-1559736dad80",
      binding: %Vyasa.Adapters.Binding{
        __meta__: #Ecto.Schema.Metadata<:loaded, "bindings">,
        id: "19ffdc82-a5d8-49c3-8b01-1559736dad80",
        w_type: nil,
        field_key: ["target", "body_translit_meant"],
        node_id: nil,
        verse_id: nil,
        verse: #Ecto.Association.NotLoaded<association :verse is not loaded>,
        chapter_no: nil,
        chapter: #Ecto.Association.NotLoaded<association :chapter is not loaded>,
        source_id: nil,
        source: #Ecto.Association.NotLoaded<association :source is not loaded>,
        translation_id: "fc80709a-39dc-4b9c-95c3-1d64ce818302",
        translation: #Ecto.Association.NotLoaded<association :translation is not loaded>,
        sheaf_id: nil,
        sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>,
        window: nil
      },
      inserted_at: ~U[2024-10-12 09:43:19Z],
      updated_at: ~U[2024-10-12 09:43:19Z]
    },
    %Vyasa.Sangh.Mark{
      __meta__: #Ecto.Schema.Metadata<:loaded, "marks">,
      id: "90c6036a-9bd1-4b65-82d5-f121ec4d7867",
      body: nil,
      order: 2,
      state: :draft,
      verse_id: nil,
      sheaf_id: "7f4ab16b-0caf-4009-ba2a-3ddded81d9aa",
      sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>,
      binding_id: "b92f990d-99a2-4f04-a2d4-d1135021ee8c",
      binding: %Vyasa.Adapters.Binding{
        __meta__: #Ecto.Schema.Metadata<:loaded, "bindings">,
        id: "b92f990d-99a2-4f04-a2d4-d1135021ee8c",
        w_type: nil,
        field_key: ["target", "body_translit_meant"],
        node_id: nil,
        verse_id: nil,
        verse: #Ecto.Association.NotLoaded<association :verse is not loaded>,
        chapter_no: nil,
        chapter: #Ecto.Association.NotLoaded<association :chapter is not loaded>,
        source_id: nil,
        source: #Ecto.Association.NotLoaded<association :source is not loaded>,
        translation_id: "97a7a662-a91b-486f-93e8-7ae932d01a1a",
        translation: #Ecto.Association.NotLoaded<association :translation is not loaded>,
        sheaf_id: nil,
        sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>,
        window: nil
      },
      inserted_at: ~U[2024-10-11 09:03:00Z],
      updated_at: ~U[2024-10-11 09:03:00Z]
    }
  ],
  inserted_at: ~N[2024-09-27 00:51:48],
  updated_at: ~N[2024-09-27 00:51:48]
}
[debug] Replied in 81ms
[debug] HANDLE EVENT "verses::focus_toggle_on_quick_mark_drafting" in VyasaWeb.ModeLive.Mediator
  Component: VyasaWeb.Context.Read
  Parameters: %{"is_focusing?" => false, "value" => ""}
[debug] Replied in 129µs
iex([email protected])17>

* marks order force

* old man mark is not feeling so good

* ReWrite how marks get initialised @ :show_verse (#119)

* Minor change in fn signature

* Add init_draft_reflector()

* Don't rely on the time async message passing

* Use custom generic_modal_wrapper

This one has more specific callback attributes and tailwind classes can
be injected to it.

* Create data and ui skeletons for sheaf_creator

* Add support for human friendly time formatting

* Setup skeleton for replyto context

Some pending todo functions for how the reply to context shall be determined

* Standardise UI, improve wrapper's default UI

* Improve generic_modal_wrapper styling slots

* Wire sheaf creation form to stubbed event handler

Relevant TODOs have been added

* Use session.name for signature, add handler stubs

* Edit marks in read mode (#118)

* Add generic debug dump component

This makes life easy when wiring things up

* Rename namespace for Context.Read.*

* Groundwork: add discuss component w sheafs

* Init Context.Components mod for common components

* Add skeletons for Sheaf Container

Container managers sheaf state within itself.
Should actually make the verse-matrix use this container, sometime.

* Minor changes, add some TODOs to share

explicit todos

Minor change

* Add live component EditableMarkDisplay

* Add UI improvements to EditableMarkDisplay

The edit button on quick draft should only be seen when the dropdown is
expanded and all the marks can be seen. The general pattern I'm trying
to follow is that buttons should only be shown when an action makes
sense. So here, if the user can't even see the marks currently
accumulating, then the user shouldn't have the chance to edit any marks.

Notice that the EditableMarkDisplay is a live_component that is a child
of a function component (collapsible_marks_display). This is so that it can keep its own state and
do it's own event-handling. I'm not sure if this is pattern-breaking.
A reference to the actual parent live_component that calls collapsible_marks_display
will always be there in case there's a need for the parent to handle
any particular events. So comms b/w live_components is still going to be
via phx-target values.

* Change <input/> -> <textarea/> fr quick_draft_form

* Add tailwind config for custom svg icons

not sure how the scaling for this works, seems like i can't just put in
the class="h-5 w-5" to do the scaling

* Let custom svg be scalable

* Subtly shift the ping indicator to control panel

* Marks ordering in Sheaf and L-Trees  (#114)

* do sheafs grow on trees

* sangh session dealing with lineage

* Solve initial order problem

* fix: ensure non-null id used @ EditableMarkDisplay

---------

Co-authored-by: ks0m1c_dharma <[email protected]>

* Trigger Diff

* TOMBSTONING

* Fix bugs and revert ui for read_mode:delete marks

1.  JIT generate id for marks yet to be inserted to the db: instead of
    using a temp id, I'm actually assigning a JIT-generated id for a
    mark even if that isn't inserted into the db yet. this has two
    benefits: div ids have meaningful static ids (e.g.
    mark-container-\<\> mark.id) regardless of whether that mark has
    been inserted into the db or not. While doing this, the changeset
    for marks has been udpated to add id as well. This fixes a bunch of
    id-based errors as well.

2.  while doing 1, it came to light that the bindHoverune handlers were
    not handling the draft mark update properly (i.e. not using the
    already existing update function in mark) . it's changed now,
    example of the diff:

    ``` diff
      @impl true
      def handle_event(
            "bindHoveRune",
            %{"binding" => bind = %{"verse_id" => verse_id}},
            %{
              assigns: %{
                kv_verses: verses,
                marks: [%Mark{state: :draft, verse_id: curr_verse_id} = d_mark | marks]
              }
            } = socket
          )
          when is_binary(curr_verse_id) and verse_id != curr_verse_id do
        # binding here blocks the stream from appending to quote
        bind = Draft.bind_node(bind)

        bound_verses =
          verses
           |> then(&put_in(&1[verse_id].binding, bind))
           |> then(&put_in(&1[curr_verse_id].binding, nil))

    +    updated_draft_mark = d_mark |> Mark.update_mark(%{binding: bind, verse_id: verse_id})
    +
         {:noreply,
          socket
          |> mutate_verses(curr_verse_id, bound_verses)
          |> mutate_verses(verse_id, bound_verses)
    -     |> assign(:marks, [%{d_mark | binding: bind, verse_id: verse_id} | marks])}
    +     |> assign(:marks, [updated_draft_mark | marks])}
       end
    ```

3.  add ui state structs: all of the relevant ui states have structs
    that are intended to be static interfaces. this felt better than
    directly keeping state within various sockets and is done with a
    view to remove live components and change them to function
    components wherever possible.

4.  bugfix for `order()`:

    - it had an off-by-one-error
    - shifted it to Vyasa.Sangh.Mark
    - also note that the order shall be 1-indexed instead of 0-indexed
      for human-friendliness

5.  minor fixes:

    1.  fix update<sub>mark</sub> default argument

        ``` diff
        -def update_mark(%Mark{} = draft_mark, opts \\ []) do
        +def update_mark(%Mark{} = draft_mark, opts \\ %{}) do
        ```

1.  In this commit, the marks<sub>ui</sub> is NOT kept by the read
    context module, that's why when I update things by create mark or
    delete mark, the ui state is not preserved and initial, default
    state is seen. This was intentionally done in this commit because
    I'm having problems with duplicate ids for verses for some reason,
    I'll show it in the next commit, so that the problem can be clearly
    seen.

* [BUGGY] keep marks_ui within ReadContext

This is buggy, not sure why there's a duplicate yet.  will come back to
it after lunch

Replication Steps:
1. delete all marks and see there's no error
2. create first mark ==> no error
3. create second mark ==> crashes due to duplicate verse id

Crash dump:

[debug] Replied in 13ms
[error] GenServer #PID<0.8416.0> terminating
** (RuntimeError) found duplicate ID "verse-7d9d588a-34fc-4f19-b974-fc32b49b6a61" for component VyasaWeb.Context.Read.VerseMatrix when rendering template
    (phoenix_live_view 1.0.0-rc.6) lib/phoenix_live_view/diff.ex:634: anonymous fn/5 in Phoenix.LiveView.Diff.render_pending_components/6
    (elixir 1.17.2) lib/enum.ex:2531: Enum."-reduce/3-lists^foldl/2-0-"/3
    (phoenix_live_view 1.0.0-rc.6) lib/phoenix_live_view/diff.ex:631: anonymous fn/4 in Phoenix.LiveView.Diff.render_pending_components/6
    (stdlib 5.2.3) maps.erl:416: :maps.fold_1/4
    (phoenix_live_view 1.0.0-rc.6) lib/phoenix_live_view/diff.ex:625: Phoenix.LiveView.Diff.render_pending_components/6
    (phoenix_live_view 1.0.0-rc.6) lib/phoenix_live_view/diff.ex:217: Phoenix.LiveView.Diff.write_component/4
    (phoenix_live_view 1.0.0-rc.6) lib/phoenix_live_view/channel.ex:662: Phoenix.LiveView.Channel.component_handle/4
    (stdlib 5.2.3) gen_server.erl:1095: :gen_server.try_handle_info/3
    (stdlib 5.2.3) gen_server.erl:1183: :gen_server.handle_msg/6
    (stdlib 5.2.3) proc_lib.erl:251: :proc_lib.wake_up/3
Last message: %Phoenix.Socket.Message{topic: "lv:phx-F_1MH_6F0ciqVqwi", event: "event", payload: %{"cid" => 3, "event" => "createMark", "type" => "form", "value" => "body=how+about+now%2C+any+duplicate%3F"}, ref: "23", join_ref: "4"}
State: %{socket: #Phoenix.LiveView.Socket<id: "phx-F_1MH_6F0ciqVqwi", endpoint: VyasaWeb.Endpoint, view: VyasaWeb.ModeLive.Mediator, parent_pid: nil, root_pid: #PID<0.8416.0>, router: VyasaWeb.Router, assigns: %{mode: %VyasaWeb.ModeLive.UserMode{mode: "read", default_ui_state: %VyasaWeb.ModeLive.UiState{show_media_bridge?: true, show_action_bar?: true}, mode_icon_name: "hero-book-open", quick_actions: [:mark_quote, :bookmark], control_panel_modes: ["discuss"], mode_actions: [:mark_quote, :bookmark], action_bar_actions: [:nav_back, :nav_fwd], action_bar_info_types: nil, action_bar_component: VyasaWeb.MediaLive.MediaBridge, action_bar_component_selector: "media-bridge", control_panel_component: VyasaWeb.ControlPanel, control_panel_component_selector: "control-panel", mode_context_component: VyasaWeb.Context.Read, mode_context_component_selector: "read"}, session: %VyasaWeb.Session{name: "ritesh kumar", id: "IhrQV0ypqg8bHakbvb2bymNF", active: true, sangh: %Vyasa.Sangh.Session{__meta__: #Ecto.Schema.Metadata<:loaded, "sessions">, id: "164eb05d-221a-4939-b180-8394e1a5515f", sheafs: #Ecto.Association.NotLoaded<association :sheafs is not loaded>, inserted_at: ~U[2024-09-27 00:51:48Z], updated_at: ~U[2024-09-27 00:51:48Z]}, last_opened: "2024-09-23T11:03:32.022987Z"}, __changed__: %{}, flash: %{}, locale: "en-GB", url_params: %{"chap_no" => "1", "source_title" => "hanuman_chalisa"}, live_action: :show_verses, ui_state: %VyasaWeb.ModeLive.UiState{show_media_bridge?: true, show_action_bar?: true}, device_type: :desktop, tz: %{timezone: "Asia/Singapore", timezone_offset: 480}}, transport_pid: #PID<0.8403.0>, ...>, components: {%{15 => {VyasaWeb.Context.Read.VerseMatrix, "verse-aa3ad88b-0de1-443e-b471-c08a44e67c61", %{id: "verse-aa3ad88b-0de1-443e-b471-c08a44e67c61", edge: [%{title: "1.10", field: [:body], verseup: {:big, "dn"}}, %{node: %Vyasa.Written.Translation{__meta__: #Ecto.Schema.Metadata<:loaded, "translations">, id: "651676b6-ffc3-41c1-b525-f376989f639e", lang: "en", type: "verses", target: %Vyasa.Written.Translation.Target{id: "dd20a94f-8f34-49f8-8da8-4321cfecf172", title: nil, title_translit: nil, body: "प्रभु चरित्र सुनिबे को रसिया ।\n\nराम लखन सीता मन बसिया ॥८॥", body_meant: nil, body_translit: "prabhu caritra sunibe ko rasiyā .\n\nrāma lakhana sītā mana basiyā ..8..", body_translit_meant: "You feel extremely delighted in listening to Lord Rama’s doings and conduct. Lord Rama, Mother Sita, and Lord Laxmana dwell forever in your heart."}, verse_id: "aa3ad88b-0de1-443e-b471-c08a44e67c61", verse: #Ecto.Association.NotLoaded<association :verse is not loaded>, chapter_no: nil, chapter: #Ecto.Association.NotLoaded<association :chapter is not loaded>, source_id: "63918acd-77a9-451a-b8d1-8d5b73208eae", source: #Ecto.Association.NotLoaded<association :source is not loaded>}, field: [:target, :body_translit], verseup: :mid}, %{node: %Vyasa.Written.Translation{__meta__: #Ecto.Schema.Metadata<:loaded, "translations">, id: "651676b6-ffc3-41c1-b525-f376989f639e", lang: "en", type: "verses", target: %Vyasa.Written.Translation.Target{id: "dd20a94f-8f34-49f8-8da8-4321cfecf172", title: nil, title_translit: nil, body: "प्रभु चरित्र सुनिबे को रसिया ।\n\nराम लखन सीता मन बसिया ॥८॥", body_meant: nil, body_translit: "prabhu caritra sunibe ko rasiyā .\n\nrāma lakhana sītā mana basiyā ..8..", body_translit_meant: "You feel extremely delighted in listening to Lord Rama’s doings and conduct. Lord Rama, Mother Sita, and Lord Laxmana dwell forever in your heart."}, verse_id: "aa3ad88b-0de1-443e-b471-c08a44e67c61", verse: #Ecto.Association.NotLoaded<association :verse is not loaded>, chapter_no: nil, chapter: #Ecto.Association.NotLoaded<association :chapter is not loaded>, source_id: "63918acd-77a9-451a-b8d1-8d5b73208eae", source: #Ecto.Association.NotLoaded<association :source is not loaded>}, field: [:target, :body_translit_meant], verseup: :mid}, %{node: %Vyasa.Written.Translation{__meta__: #Ecto.Schema.Metadata<:loaded, "translations">, id: "651676b6-ffc3-41c1-b525-f376989f639e", lang: "en", type: "verses", target: %Vyasa.Written.Translation.Target{id: "dd20a94f-8f34-49f8-8da8-4321cfecf172", title: nil, title_translit: nil, body: "प्रभु चरित्र सुनिबे को रसिया ।\n\nराम लखन सीता मन बसिया ॥८॥", body_meant: nil, body_translit: "prabhu caritra sunibe ko rasiyā .\n\nrāma lakhana sītā mana basiyā ..8..", body_translit_meant: "You feel extremely delighted in listening to Lord Rama’s doings and conduct. Lord Rama, Mother Sita, and Lord Laxmana dwell forever in your heart."}, verse_id: "aa3ad88b-0de1-443e-b471-c08a44e67c61", verse: #Ecto.Association.NotLoaded<association :verse is not loaded>, chapter_no: nil, chapter: #Ecto.Association.NotLoaded<association :chapter is not loaded>, source_id: "63918acd-77a9-451a-b8d1-8d5b73208eae", source: #Ecto.Association.NotLoaded<association :source is not loaded>}, field: [:target, :body], verseup: :mid}], __changed__: %{}, flash: %{}, marks: [%Vyasa.Sangh.Mark{__meta__: #Ecto.Schema.Metadata<:loaded, "marks">, id: "5dfdb167-6c57-46dd-a0c4-10b52cb03a85", body: "wonderful", order: 2, state: :live, verse_id: nil, sheaf_id: "7f4ab16b-0caf-4009-ba2a-3ddded81d9aa", sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>, binding_id: "001da594-3808-46cf-9b9c-5dfb3559780e", binding: %Vyasa.Adapters.Binding{__meta__: #Ecto.Schema.Metadata<:loaded, "bindings">, id: "001da594-3808-46cf-9b9c-5dfb3559780e", w_type: nil, field_key: ["target", "body_translit_meant"], node_id: nil, verse_id: nil, verse: #Ecto.Association.NotLoaded<association :verse is not loaded>, chapter_no: nil, chapter: #Ecto.Association.NotLoaded<association :chapter is not loaded>, source_id: nil, source: #Ecto.Association.NotLoaded<association :source is not loaded>, translation_id: "97a7a662-a91b-486f-93e8-7ae932d01a1a", translation: #Ecto.Association.NotLoaded<association :translation is not loaded>, sheaf_id: nil, sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>, window: nil}, inserted_at: ~U[2024-10-11 04:31:50Z], updated_at: ~U[2024-10-11 04:31:50Z]}, %Vyasa.Sangh.Mark{__meta__: #Ecto.Schema.Metadata<:loaded, "marks">, id: "273a093d-4f90-40a4-b19a-2f8f7825d201", body: "truncated utc datetime", order: 1, state: :live, verse_id: nil, sheaf_id: "7f4ab16b-0caf-4009-ba2a-3ddded81d9aa", sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>, binding_id: "ef39315b-530c-4841-ba32-86773f451727", binding: %Vyasa.Adapt (truncated)
[debug] MOUNT VyasaWeb.ModeLive.Mediator
  Parameters: %{"chap_no" => "1", "source_title" => "hanuman_chalisa"}
  Session: %{"_csrf_token" => "DJ-RIoXwEzHW82rbb21le_8k"}
[debug] QUERY OK source="sessions" db=3.5ms idle=1690.4ms
SELECT s0."id", s0."inserted_at", s0."updated_at" FROM "sessions" AS s0 WHERE (s0."id" = $1) ["164eb05d-221a-4939-b180-8394e1a5515f"]
↳

* Fix duplicate id issue on verse matrix

* Standardise use of @event_target, cleanups

When using @event_target, the intent is that phx-target values
will be passed around. This must be agnostic to the 2 main ways of
supplying that argument, as a HTML selector, or as a module name (or @myself).
Therefore, we should discourage ourselves from doing format-strings at
the point of the @event_target being supplied as an argument, meaning:

good, because agnostic:
phx-target={@event_target}

bad, because hardcoded:
phx-target={"#" <> @event_target}
* in this case, the event trigger will throw a dom error.

* [Attempt]: Sanitise, defrag orders in marks-list

If this is an anti-pattern, then this commit should be reverted.

* UI fixes: hide buttons on marks when !is_editable?

* Add in stub event handlers to prevent crashes

Temporary stuff, will be addressed in immediate-next PR

* Minor changes

* Toggle edit state for marks content

* Partial implementation of edit marks

the form stuff doesn't exist so it's not wired up yet. To be frank,
im' not sure how to set up a form without it needing to hold state.

* [BUGGY] Wire up form update for edit

this does the following:
1. wires up the form like how we usedd it in createMark
2. actually captures the event properly within the event handler,
everything looks good at that point, even the edit_mark_in_marks
function on inspection looks good
3. the marks is getting assigned to properly because the newly edited
mark content is seen after doing a dom refresh
4. HOWEVER, the print statement at the sheaf_update function DOES NOT
show the correct, updated marks in the sheaf

here's a dump for it for reference

[debug] HANDLE EVENT "editMarkContent" in VyasaWeb.ModeLive.Mediator
  Component: VyasaWeb.Context.Read
  Parameters: %{"mark_id" => "02218551-591f-4450-abbd-a7b7d76fd48e"}
[debug] Replied in 2ms
[debug] HANDLE EVENT "editMarkContent" in VyasaWeb.ModeLive.Mediator
  Component: VyasaWeb.Context.Read
  Parameters: %{"mark_body" => "  testing\n\n\nwhat hte heck", "mark_id" => "02218551-591f-4450-abbd-a7b7d76fd48e"}
>>> UPDATE SHEAF -- SHOULD BE WRITING TO DB NOW: %Vyasa.Sangh.Sheaf{
  __meta__: #Ecto.Schema.Metadata<:loaded, "sheafs">,
  id: "7f4ab16b-0caf-4009-ba2a-3ddded81d9aa",
  body: nil,
  active: true,
  path: %EctoLtree.LabelTree{labels: ["7f4ab16b"]},
  signature: nil,
  traits: ["draft"],
  child_count: 0,
  session_id: "164eb05d-221a-4939-b180-8394e1a5515f",
  session: #Ecto.Association.NotLoaded<association :session is not loaded>,
  parent_id: nil,
  parent: #Ecto.Association.NotLoaded<association :parent is not loaded>,
  marks: [
    %Vyasa.Sangh.Mark{
      __meta__: #Ecto.Schema.Metadata<:loaded, "marks">,
      id: "555eb625-e392-496e-9831-4f4c130be6fd",
      body: "wonderful stuff",
      order: 5,
      state: :live,
      verse_id: nil,
      sheaf_id: "7f4ab16b-0caf-4009-ba2a-3ddded81d9aa",
      sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>,
      binding_id: "072124d0-5e27-4601-832f-35eaa6426879",
      binding: %Vyasa.Adapters.Binding{
        __meta__: #Ecto.Schema.Metadata<:loaded, "bindings">,
        id: "072124d0-5e27-4601-832f-35eaa6426879",
        w_type: nil,
        field_key: ["target", "body_translit_meant"],
        node_id: nil,
        verse_id: nil,
        verse: #Ecto.Association.NotLoaded<association :verse is not loaded>,
        chapter_no: nil,
        chapter: #Ecto.Association.NotLoaded<association :chapter is not loaded>,
        source_id: nil,
        source: #Ecto.Association.NotLoaded<association :source is not loaded>,
        translation_id: "97a7a662-a91b-486f-93e8-7ae932d01a1a",
        translation: #Ecto.Association.NotLoaded<association :translation is not loaded>,
        sheaf_id: nil,
        sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>,
        window: nil
      },
      inserted_at: ~U[2024-10-12 08:46:54Z],
      updated_at: ~U[2024-10-12 08:46:54Z]
    },
    %Vyasa.Sangh.Mark{
      __meta__: #Ecto.Schema.Metadata<:loaded, "marks">,
      id: "b22a5661-8268-4875-be26-a12256414136",
      body: nil,
      order: 5,
      state: :draft,
      verse_id: nil,
      sheaf_id: "7f4ab16b-0caf-4009-ba2a-3ddded81d9aa",
      sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>,
      binding_id: "90e18044-73b2-4ede-a149-a381de893b9f",
      binding: %Vyasa.Adapters.Binding{
        __meta__: #Ecto.Schema.Metadata<:loaded, "bindings">,
        id: "90e18044-73b2-4ede-a149-a381de893b9f",
        w_type: nil,
        field_key: ["target", "body_translit_meant"],
        node_id: nil,
        verse_id: nil,
        verse: #Ecto.Association.NotLoaded<association :verse is not loaded>,
        chapter_no: nil,
        chapter: #Ecto.Association.NotLoaded<association :chapter is not loaded>,
        source_id: nil,
        source: #Ecto.Association.NotLoaded<association :source is not loaded>,
        translation_id: "fc80709a-39dc-4b9c-95c3-1d64ce818302",
        translation: #Ecto.Association.NotLoaded<association :translation is not loaded>,
        sheaf_id: nil,
        sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>,
        window: nil
      },
      inserted_at: ~U[2024-10-12 09:52:40Z],
      updated_at: ~U[2024-10-12 09:52:40Z]
    },
    %Vyasa.Sangh.Mark{
      __meta__: #Ecto.Schema.Metadata<:loaded, "marks">,
      id: "8af43833-575c-4eb8-83b1-eb4e58509e4c",
      body: nil,
      order: 4,
      state: :draft,
      verse_id: nil,
      sheaf_id: "7f4ab16b-0caf-4009-ba2a-3ddded81d9aa",
      sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>,
      binding_id: "23b70937-ed81-47fe-a560-ee14287bff7d",
      binding: %Vyasa.Adapters.Binding{
        __meta__: #Ecto.Schema.Metadata<:loaded, "bindings">,
        id: "23b70937-ed81-47fe-a560-ee14287bff7d",
        w_type: nil,
        field_key: ["target", "body_translit_meant"],
        node_id: nil,
        verse_id: nil,
        verse: #Ecto.Association.NotLoaded<association :verse is not loaded>,
        chapter_no: nil,
        chapter: #Ecto.Association.NotLoaded<association :chapter is not loaded>,
        source_id: nil,
        source: #Ecto.Association.NotLoaded<association :source is not loaded>,
        translation_id: "97a7a662-a91b-486f-93e8-7ae932d01a1a",
        translation: #Ecto.Association.NotLoaded<association :translation is not loaded>,
        sheaf_id: nil,
        sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>,
        window: nil
      },
      inserted_at: ~U[2024-10-12 09:46:13Z],
      updated_at: ~U[2024-10-12 09:46:13Z]
    },
    %Vyasa.Sangh.Mark{
      __meta__: #Ecto.Schema.Metadata<:loaded, "marks">,
      id: "c7ad47e6-629d-4382-936d-64d757772c4e",
      body: nil,
      order: 3,
      state: :draft,
      verse_id: nil,
      sheaf_id: "7f4ab16b-0caf-4009-ba2a-3ddded81d9aa",
      sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>,
      binding_id: "d5758230-7966-4f9b-8c16-ae13998cd71b",
      binding: %Vyasa.Adapters.Binding{
        __meta__: #Ecto.Schema.Metadata<:loaded, "bindings">,
        id: "d5758230-7966-4f9b-8c16-ae13998cd71b",
        w_type: nil,
        field_key: ["target", "body_translit_meant"],
        node_id: nil,
        verse_id: nil,
        verse: #Ecto.Association.NotLoaded<association :verse is not loaded>,
        chapter_no: nil,
        chapter: #Ecto.Association.NotLoaded<association :chapter is not loaded>,
        source_id: nil,
        source: #Ecto.Association.NotLoaded<association :source is not loaded>,
        translation_id: "fc80709a-39dc-4b9c-95c3-1d64ce818302",
        translation: #Ecto.Association.NotLoaded<association :translation is not loaded>,
        sheaf_id: nil,
        sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>,
        window: nil
      },
      inserted_at: ~U[2024-10-12 09:44:09Z],
      updated_at: ~U[2024-10-12 09:44:09Z]
    },
    %Vyasa.Sangh.Mark{
      __meta__: #Ecto.Schema.Metadata<:loaded, "marks">,
      id: "02218551-591f-4450-abbd-a7b7d76fd48e",
      body: "testing",
      order: 2,
      state: :live,
      verse_id: nil,
      sheaf_id: "7f4ab16b-0caf-4009-ba2a-3ddded81d9aa",
      sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>,
      binding_id: "19ffdc82-a5d8-49c3-8b01-1559736dad80",
      binding: %Vyasa.Adapters.Binding{
        __meta__: #Ecto.Schema.Metadata<:loaded, "bindings">,
        id: "19ffdc82-a5d8-49c3-8b01-1559736dad80",
        w_type: nil,
        field_key: ["target", "body_translit_meant"],
        node_id: nil,
        verse_id: nil,
        verse: #Ecto.Association.NotLoaded<association :verse is not loaded>,
        chapter_no: nil,
        chapter: #Ecto.Association.NotLoaded<association :chapter is not loaded>,
        source_id: nil,
        source: #Ecto.Association.NotLoaded<association :source is not loaded>,
        translation_id: "fc80709a-39dc-4b9c-95c3-1d64ce818302",
        translation: #Ecto.Association.NotLoaded<association :translation is not loaded>,
        sheaf_id: nil,
        sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>,
        window: nil
      },
      inserted_at: ~U[2024-10-12 09:43:19Z],
      updated_at: ~U[2024-10-12 09:43:19Z]
    },
    %Vyasa.Sangh.Mark{
      __meta__: #Ecto.Schema.Metadata<:loaded, "marks">,
      id: "90c6036a-9bd1-4b65-82d5-f121ec4d7867",
      body: nil,
      order: 2,
      state: :draft,
      verse_id: nil,
      sheaf_id: "7f4ab16b-0caf-4009-ba2a-3ddded81d9aa",
      sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>,
      binding_id: "b92f990d-99a2-4f04-a2d4-d1135021ee8c",
      binding: %Vyasa.Adapters.Binding{
        __meta__: #Ecto.Schema.Metadata<:loaded, "bindings">,
        id: "b92f990d-99a2-4f04-a2d4-d1135021ee8c",
        w_type: nil,
        field_key: ["target", "body_translit_meant"],
        node_id: nil,
        verse_id: nil,
        verse: #Ecto.Association.NotLoaded<association :verse is not loaded>,
        chapter_no: nil,
        chapter: #Ecto.Association.NotLoaded<association :chapter is not loaded>,
        source_id: nil,
        source: #Ecto.Association.NotLoaded<association :source is not loaded>,
        translation_id: "97a7a662-a91b-486f-93e8-7ae932d01a1a",
        translation: #Ecto.Association.NotLoaded<association :translation is not loaded>,
        sheaf_id: nil,
        sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>,
        window: nil
      },
      inserted_at: ~U[2024-10-11 09:03:00Z],
      updated_at: ~U[2024-10-11 09:03:00Z]
    }
  ],
  inserted_at: ~N[2024-09-27 00:51:48],
  updated_at: ~N[2024-09-27 00:51:48]
}
[debug] Replied in 81ms
[debug] HANDLE EVENT "verses::focus_toggle_on_quick_mark_drafting" in VyasaWeb.ModeLive.Mediator
  Component: VyasaWeb.Context.Read
  Parameters: %{"is_focusing?" => false, "value" => ""}
[debug] Replied in 129µs
iex([email protected])17>

* marks order force

* old man mark is not feeling so good

* ReWrite how marks get initialised @ :show_verse (#119)

* Minor change in fn signature

* Add init_draft_reflector()

---------

Co-authored-by: ks0m1c_dharma <[email protected]>

* Minor changes

* Add a generic modal wrapper (#120)

* Add generic debug dump component

This makes life easy when wiring things up

* Rename namespace for Context.Read.*

* Groundwork: add discuss component w sheafs

* Init Context.Components mod for common components

* Add skeletons for Sheaf Container

Container managers sheaf state within itself.
Should actually make the verse-matrix use this container, sometime.

* Minor changes, add some TODOs to share

explicit todos

Minor change

* Add live component EditableMarkDisplay

* Add UI improvements to EditableMarkDisplay

The edit button on quick draft should only be seen when the dropdown is
expanded and all the marks can be seen. The general pattern I'm trying
to follow is that buttons should only be shown when an action makes
sense. So here, if the user can't even see the marks currently
accumulating, then the user shouldn't have the chance to edit any marks.

Notice that the EditableMarkDisplay is a live_component that is a child
of a function component (collapsible_marks_display). This is so that it can keep its own state and
do it's own event-handling. I'm not sure if this is pattern-breaking.
A reference to the actual parent live_component that calls collapsible_marks_display
will always be there in case there's a need for the parent to handle
any particular events. So comms b/w live_components is still going to be
via phx-target values.

* Change <input/> -> <textarea/> fr quick_draft_form

* Add tailwind config for custom svg icons

not sure how the scaling for this works, seems like i can't just put in
the class="h-5 w-5" to do the scaling

* Let custom svg be scalable

* Subtly shift the ping indicator to control panel

* Marks ordering in Sheaf and L-Trees  (#114)

* do sheafs grow on trees

* sangh session dealing with lineage

* Solve initial order problem

* fix: ensure non-null id used @ EditableMarkDisplay

---------

Co-authored-by: ks0m1c_dharma <[email protected]>

* Trigger Diff

* TOMBSTONING

* Fix bugs and revert ui for read_mode:delete marks

1.  JIT generate id for marks yet to be inserted to the db: instead of
    using a temp id, I'm actually assigning a JIT-generated id for a
    mark even if that isn't inserted into the db yet. this has two
    benefits: div ids have meaningful static ids (e.g.
    mark-container-\<\> mark.id) regardless of whether that mark has
    been inserted into the db or not. While doing this, the changeset
    for marks has been udpated to add id as well. This fixes a bunch of
    id-based errors as well.

2.  while doing 1, it came to light that the bindHoverune handlers were
    not handling the draft mark update properly (i.e. not using the
    already existing update function in mark) . it's changed now,
    example of the diff:

    ``` diff
      @impl true
      def handle_event(
            "bindHoveRune",
            %{"binding" => bind = %{"verse_id" => verse_id}},
            %{
              assigns: %{
                kv_verses: verses,
                marks: [%Mark{state: :draft, verse_id: curr_verse_id} = d_mark | marks]
              }
            } = socket
          )
          when is_binary(curr_verse_id) and verse_id != curr_verse_id do
        # binding here blocks the stream from appending to quote
        bind = Draft.bind_node(bind)

        bound_verses =
          verses
           |> then(&put_in(&1[verse_id].binding, bind))
           |> then(&put_in(&1[curr_verse_id].binding, nil))

    +    updated_draft_mark = d_mark |> Mark.update_mark(%{binding: bind, verse_id: verse_id})
    +
         {:noreply,
          socket
          |> mutate_verses(curr_verse_id, bound_verses)
          |> mutate_verses(verse_id, bound_verses)
    -     |> assign(:marks, [%{d_mark | binding: bind, verse_id: verse_id} | marks])}
    +     |> assign(:marks, [updated_draft_mark | marks])}
       end
    ```

3.  add ui state structs: all of the relevant ui states have structs
    that are intended to be static interfaces. this felt better than
    directly keeping state within various sockets and is done with a
    view to remove live components and change them to function
    components wherever possible.

4.  bugfix for `order()`:

    - it had an off-by-one-error
    - shifted it to Vyasa.Sangh.Mark
    - also note that the order shall be 1-indexed instead of 0-indexed
      for human-friendliness

5.  minor fixes:

    1.  fix update<sub>mark</sub> default argument

        ``` diff
        -def update_mark(%Mark{} = draft_mark, opts \\ []) do
        +def update_mark(%Mark{} = draft_mark, opts \\ %{}) do
        ```

1.  In this commit, the marks<sub>ui</sub> is NOT kept by the read
    context module, that's why when I update things by create mark or
    delete mark, the ui state is not preserved and initial, default
    state is seen. This was intentionally done in this commit because
    I'm having problems with duplicate ids for verses for some reason,
    I'll show it in the next commit, so that the problem can be clearly
    seen.

* [BUGGY] keep marks_ui within ReadContext

This is buggy, not sure why there's a duplicate yet.  will come back to
it after lunch

Replication Steps:
1. delete all marks and see there's no error
2. create first mark ==> no error
3. create second mark ==> crashes due to duplicate verse id

Crash dump:

[debug] Replied in 13ms
[error] GenServer #PID<0.8416.0> terminating
** (RuntimeError) found duplicate ID "verse-7d9d588a-34fc-4f19-b974-fc32b49b6a61" for component VyasaWeb.Context.Read.VerseMatrix when rendering template
    (phoenix_live_view 1.0.0-rc.6) lib/phoenix_live_view/diff.ex:634: anonymous fn/5 in Phoenix.LiveView.Diff.render_pending_components/6
    (elixir 1.17.2) lib/enum.ex:2531: Enum."-reduce/3-lists^foldl/2-0-"/3
    (phoenix_live_view 1.0.0-rc.6) lib/phoenix_live_view/diff.ex:631: anonymous fn/4 in Phoenix.LiveView.Diff.render_pending_components/6
    (stdlib 5.2.3) maps.erl:416: :maps.fold_1/4
    (phoenix_live_view 1.0.0-rc.6) lib/phoenix_live_view/diff.ex:625: Phoenix.LiveView.Diff.render_pending_components/6
    (phoenix_live_view 1.0.0-rc.6) lib/phoenix_live_view/diff.ex:217: Phoenix.LiveView.Diff.write_component/4
    (phoenix_live_view 1.0.0-rc.6) lib/phoenix_live_view/channel.ex:662: Phoenix.LiveView.Channel.component_handle/4
    (stdlib 5.2.3) gen_server.erl:1095: :gen_server.try_handle_info/3
    (stdlib 5.2.3) gen_server.erl:1183: :gen_server.handle_msg/6
    (stdlib 5.2.3) proc_lib.erl:251: :proc_lib.wake_up/3
Last message: %Phoenix.Socket.Message{topic: "lv:phx-F_1MH_6F0ciqVqwi", event: "event", payload: %{"cid" => 3, "event" => "createMark", "type" => "form", "value" => "body=how+about+now%2C+any+duplicate%3F"}, ref: "23", join_ref: "4"}
State: %{socket: #Phoenix.LiveView.Socket<id: "phx-F_1MH_6F0ciqVqwi", endpoint: VyasaWeb.Endpoint, view: VyasaWeb.ModeLive.Mediator, parent_pid: nil, root_pid: #PID<0.8416.0>, router: VyasaWeb.Router, assigns: %{mode: %VyasaWeb.ModeLive.UserMode{mode: "read", default_ui_state: %VyasaWeb.ModeLive.UiState{show_media_bridge?: true, show_action_bar?: true}, mode_icon_name: "hero-book-open", quick_actions: [:mark_quote, :bookmark], control_panel_modes: ["discuss"], mode_actions: [:mark_quote, :bookmark], action_bar_actions: [:nav_back, :nav_fwd], action_bar_info_types: nil, action_bar_component: VyasaWeb.MediaLive.MediaBridge, action_bar_component_selector: "media-bridge", control_panel_component: VyasaWeb.ControlPanel, control_panel_component_selector: "control-panel", mode_context_component: VyasaWeb.Context.Read, mode_context_component_selector: "read"}, session: %VyasaWeb.Session{name: "ritesh kumar", id: "IhrQV0ypqg8bHakbvb2bymNF", active: true, sangh: %Vyasa.Sangh.Session{__meta__: #Ecto.Schema.Metadata<:loaded, "sessions">, id: "164eb05d-221a-4939-b180-8394e1a5515f", sheafs: #Ecto.Association.NotLoaded<association :sheafs is not loaded>, inserted_at: ~U[2024-09-27 00:51:48Z], updated_at: ~U[2024-09-27 00:51:48Z]}, last_opened: "2024-09-23T11:03:32.022987Z"}, __changed__: %{}, flash: %{}, locale: "en-GB", url_params: %{"chap_no" => "1", "source_title" => "hanuman_chalisa"}, live_action: :show_verses, ui_state: %VyasaWeb.ModeLive.UiState{show_media_bridge?: true, show_action_bar?: true}, device_type: :desktop, tz: %{timezone: "Asia/Singapore", timezone_offset: 480}}, transport_pid: #PID<0.8403.0>, ...>, components: {%{15 => {VyasaWeb.Context.Read.VerseMatrix, "verse-aa3ad88b-0de1-443e-b471-c08a44e67c61", %{id: "verse-aa3ad88b-0de1-443e-b471-c08a44e67c61", edge: [%{title: "1.10", field: [:body], verseup: {:big, "dn"}}, %{node: %Vyasa.Written.Translation{__meta__: #Ecto.Schema.Metadata<:loaded, "translations">, id: "651676b6-ffc3-41c1-b525-f376989f639e", lang: "en", type: "verses", target: %Vyasa.Written.Translation.Target{id: "dd20a94f-8f34-49f8-8da8-4321cfecf172", title: nil, title_translit: nil, body: "प्रभु चरित्र सुनिबे को रसिया ।\n\nराम लखन सीता मन बसिया ॥८॥", body_meant: nil, body_translit: "prabhu caritra sunibe ko rasiyā .\n\nrāma lakhana sītā mana basiyā ..8..", body_translit_meant: "You feel extremely delighted in listening to Lord Rama’s doings and conduct. Lord Rama, Mother Sita, and Lord Laxmana dwell forever in your heart."}, verse_id: "aa3ad88b-0de1-443e-b471-c08a44e67c61", verse: #Ecto.Association.NotLoaded<association :verse is not loaded>, chapter_no: nil, chapter: #Ecto.Association.NotLoaded<association :chapter is not loaded>, source_id: "63918acd-77a9-451a-b8d1-8d5b73208eae", source: #Ecto.Association.NotLoaded<association :source is not loaded>}, field: [:target, :body_translit], verseup: :mid}, %{node: %Vyasa.Written.Translation{__meta__: #Ecto.Schema.Metadata<:loaded, "translations">, id: "651676b6-ffc3-41c1-b525-f376989f639e", lang: "en", type: "verses", target: %Vyasa.Written.Translation.Target{id: "dd20a94f-8f34-49f8-8da8-4321cfecf172", title: nil, title_translit: nil, body: "प्रभु चरित्र सुनिबे को रसिया ।\n\nराम लखन सीता मन बसिया ॥८॥", body_meant: nil, body_translit: "prabhu caritra sunibe ko rasiyā .\n\nrāma lakhana sītā mana basiyā ..8..", body_translit_meant: "You feel extremely delighted in listening to Lord Rama’s doings and conduct. Lord Rama, Mother Sita, and Lord Laxmana dwell forever in your heart."}, verse_id: "aa3ad88b-0de1-443e-b471-c08a44e67c61", verse: #Ecto.Association.NotLoaded<association :verse is not loaded>, chapter_no: nil, chapter: #Ecto.Association.NotLoaded<association :chapter is not loaded>, source_id: "63918acd-77a9-451a-b8d1-8d5b73208eae", source: #Ecto.Association.NotLoaded<association :source is not loaded>}, field: [:target, :body_translit_meant], verseup: :mid}, %{node: %Vyasa.Written.Translation{__meta__: #Ecto.Schema.Metadata<:loaded, "translations">, id: "651676b6-ffc3-41c1-b525-f376989f639e", lang: "en", type: "verses", target: %Vyasa.Written.Translation.Target{id: "dd20a94f-8f34-49f8-8da8-4321cfecf172", title: nil, title_translit: nil, body: "प्रभु चरित्र सुनिबे को रसिया ।\n\nराम लखन सीता मन बसिया ॥८॥", body_meant: nil, body_translit: "prabhu caritra sunibe ko rasiyā .\n\nrāma lakhana sītā mana basiyā ..8..", body_translit_meant: "You feel extremely delighted in listening to Lord Rama’s doings and conduct. Lord Rama, Mother Sita, and Lord Laxmana dwell forever in your heart."}, verse_id: "aa3ad88b-0de1-443e-b471-c08a44e67c61", verse: #Ecto.Association.NotLoaded<association :verse is not loaded>, chapter_no: nil, chapter: #Ecto.Association.NotLoaded<association :chapter is not loaded>, source_id: "63918acd-77a9-451a-b8d1-8d5b73208eae", source: #Ecto.Association.NotLoaded<association :source is not loaded>}, field: [:target, :body], verseup: :mid}], __changed__: %{}, flash: %{}, marks: [%Vyasa.Sangh.Mark{__meta__: #Ecto.Schema.Metadata<:loaded, "marks">, id: "5dfdb167-6c57-46dd-a0c4-10b52cb03a85", body: "wonderful", order: 2, state: :live, verse_id: nil, sheaf_id: "7f4ab16b-0caf-4009-ba2a-3ddded81d9aa", sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>, binding_id: "001da594-3808-46cf-9b9c-5dfb3559780e", binding: %Vyasa.Adapters.Binding{__meta__: #Ecto.Schema.Metadata<:loaded, "bindings">, id: "001da594-3808-46cf-9b9c-5dfb3559780e", w_type: nil, field_key: ["target", "body_translit_meant"], node_id: nil, verse_id: nil, verse: #Ecto.Association.NotLoaded<association :verse is not loaded>, chapter_no: nil, chapter: #Ecto.Association.NotLoaded<association :chapter is not loaded>, source_id: nil, source: #Ecto.Association.NotLoaded<association :source is not loaded>, translation_id: "97a7a662-a91b-486f-93e8-7ae932d01a1a", translation: #Ecto.Association.NotLoaded<association :translation is not loaded>, sheaf_id: nil, sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>, window: nil}, inserted_at: ~U[2024-10-11 04:31:50Z], updated_at: ~U[2024-10-11 04:31:50Z]}, %Vyasa.Sangh.Mark{__meta__: #Ecto.Schema.Metadata<:loaded, "marks">, id: "273a093d-4f90-40a4-b19a-2f8f7825d201", body: "truncated utc datetime", order: 1, state: :live, verse_id: nil, sheaf_id: "7f4ab16b-0caf-4009-ba2a-3ddded81d9aa", sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>, binding_id: "ef39315b-530c-4841-ba32-86773f451727", binding: %Vyasa.Adapt (truncated)
[debug] MOUNT VyasaWeb.ModeLive.Mediator
  Parameters: %{"chap_no" => "1", "source_title" => "hanuman_chalisa"}
  Session: %{"_csrf_token" => "DJ-RIoXwEzHW82rbb21le_8k"}
[debug] QUERY OK source="sessions" db=3.5ms idle=1690.4ms
SELECT s0."id", s0."inserted_at", s0."updated_at" FROM "sessions" AS s0 WHERE (s0."id" = $1) ["164eb05d-221a-4939-b180-8394e1a5515f"]
↳

* Fix duplicate id issue on verse matrix

* Standardise use of @event_target, cleanups

When using @event_target, the intent is that phx-target values
will be passed around. This must be agnostic to the 2 main ways of
supplying that argument, as a HTML selector, or as a module name (or @myself).
Therefore, we should discourage ourselves from doing format-strings at
the point of the @event_target being supplied as an argument, meaning:

good, because agnostic:
phx-target={@event_target}

bad, because hardcoded:
phx-target={"#" <> @event_target}
* in this case, the event trigger will …
* Add generic debug dump component

This makes life easy when wiring things up

* Rename namespace for Context.Read.*

* Groundwork: add discuss component w sheafs

* Init Context.Components mod for common components

* Add skeletons for Sheaf Container

Container managers sheaf state within itself.
Should actually make the verse-matrix use this container, sometime.

* Minor changes, add some TODOs to share

explicit todos

Minor change

* Add live component EditableMarkDisplay

* Add UI improvements to EditableMarkDisplay

The edit button on quick draft should only be seen when the dropdown is
expanded and all the marks can be seen. The general pattern I'm trying
to follow is that buttons should only be shown when an action makes
sense. So here, if the user can't even see the marks currently
accumulating, then the user shouldn't have the chance to edit any marks.

Notice that the EditableMarkDisplay is a live_component that is a child
of a function component (collapsible_marks_display). This is so that it can keep its own state and
do it's own event-handling. I'm not sure if this is pattern-breaking.
A reference to the actual parent live_component that calls collapsible_marks_display
will always be there in case there's a need for the parent to handle
any particular events. So comms b/w live_components is still going to be
via phx-target values.

* Change <input/> -> <textarea/> fr quick_draft_form

* Add tailwind config for custom svg icons

not sure how the scaling for this works, seems like i can't just put in
the class="h-5 w-5" to do the scaling

* Let custom svg be scalable

* Subtly shift the ping indicator to control panel

* Marks ordering in Sheaf and L-Trees  (#114)

* do sheafs grow on trees

* sangh session dealing with lineage

* Solve initial order problem

* fix: ensure non-null id used @ EditableMarkDisplay

---------

Co-authored-by: ks0m1c_dharma <[email protected]>

* Trigger Diff

* TOMBSTONING

* Fix bugs and revert ui for read_mode:delete marks

1.  JIT generate id for marks yet to be inserted to the db: instead of
    using a temp id, I'm actually assigning a JIT-generated id for a
    mark even if that isn't inserted into the db yet. this has two
    benefits: div ids have meaningful static ids (e.g.
    mark-container-\<\> mark.id) regardless of whether that mark has
    been inserted into the db or not. While doing this, the changeset
    for marks has been udpated to add id as well. This fixes a bunch of
    id-based errors as well.

2.  while doing 1, it came to light that the bindHoverune handlers were
    not handling the draft mark update properly (i.e. not using the
    already existing update function in mark) . it's changed now,
    example of the diff:

    ``` diff
      @impl true
      def handle_event(
            "bindHoveRune",
            %{"binding" => bind = %{"verse_id" => verse_id}},
            %{
              assigns: %{
                kv_verses: verses,
                marks: [%Mark{state: :draft, verse_id: curr_verse_id} = d_mark | marks]
              }
            } = socket
          )
          when is_binary(curr_verse_id) and verse_id != curr_verse_id do
        # binding here blocks the stream from appending to quote
        bind = Draft.bind_node(bind)

        bound_verses =
          verses
           |> then(&put_in(&1[verse_id].binding, bind))
           |> then(&put_in(&1[curr_verse_id].binding, nil))

    +    updated_draft_mark = d_mark |> Mark.update_mark(%{binding: bind, verse_id: verse_id})
    +
         {:noreply,
          socket
          |> mutate_verses(curr_verse_id, bound_verses)
          |> mutate_verses(verse_id, bound_verses)
    -     |> assign(:marks, [%{d_mark | binding: bind, verse_id: verse_id} | marks])}
    +     |> assign(:marks, [updated_draft_mark | marks])}
       end
    ```

3.  add ui state structs: all of the relevant ui states have structs
    that are intended to be static interfaces. this felt better than
    directly keeping state within various sockets and is done with a
    view to remove live components and change them to function
    components wherever possible.

4.  bugfix for `order()`:

    - it had an off-by-one-error
    - shifted it to Vyasa.Sangh.Mark
    - also note that the order shall be 1-indexed instead of 0-indexed
      for human-friendliness

5.  minor fixes:

    1.  fix update<sub>mark</sub> default argument

        ``` diff
        -def update_mark(%Mark{} = draft_mark, opts \\ []) do
        +def update_mark(%Mark{} = draft_mark, opts \\ %{}) do
        ```

1.  In this commit, the marks<sub>ui</sub> is NOT kept by the read
    context module, that's why when I update things by create mark or
    delete mark, the ui state is not preserved and initial, default
    state is seen. This was intentionally done in this commit because
    I'm having problems with duplicate ids for verses for some reason,
    I'll show it in the next commit, so that the problem can be clearly
    seen.

* [BUGGY] keep marks_ui within ReadContext

This is buggy, not sure why there's a duplicate yet.  will come back to
it after lunch

Replication Steps:
1. delete all marks and see there's no error
2. create first mark ==> no error
3. create second mark ==> crashes due to duplicate verse id

Crash dump:

[debug] Replied in 13ms
[error] GenServer #PID<0.8416.0> terminating
** (RuntimeError) found duplicate ID "verse-7d9d588a-34fc-4f19-b974-fc32b49b6a61" for component VyasaWeb.Context.Read.VerseMatrix when rendering template
    (phoenix_live_view 1.0.0-rc.6) lib/phoenix_live_view/diff.ex:634: anonymous fn/5 in Phoenix.LiveView.Diff.render_pending_components/6
    (elixir 1.17.2) lib/enum.ex:2531: Enum."-reduce/3-lists^foldl/2-0-"/3
    (phoenix_live_view 1.0.0-rc.6) lib/phoenix_live_view/diff.ex:631: anonymous fn/4 in Phoenix.LiveView.Diff.render_pending_components/6
    (stdlib 5.2.3) maps.erl:416: :maps.fold_1/4
    (phoenix_live_view 1.0.0-rc.6) lib/phoenix_live_view/diff.ex:625: Phoenix.LiveView.Diff.render_pending_components/6
    (phoenix_live_view 1.0.0-rc.6) lib/phoenix_live_view/diff.ex:217: Phoenix.LiveView.Diff.write_component/4
    (phoenix_live_view 1.0.0-rc.6) lib/phoenix_live_view/channel.ex:662: Phoenix.LiveView.Channel.component_handle/4
    (stdlib 5.2.3) gen_server.erl:1095: :gen_server.try_handle_info/3
    (stdlib 5.2.3) gen_server.erl:1183: :gen_server.handle_msg/6
    (stdlib 5.2.3) proc_lib.erl:251: :proc_lib.wake_up/3
Last message: %Phoenix.Socket.Message{topic: "lv:phx-F_1MH_6F0ciqVqwi", event: "event", payload: %{"cid" => 3, "event" => "createMark", "type" => "form", "value" => "body=how+about+now%2C+any+duplicate%3F"}, ref: "23", join_ref: "4"}
State: %{socket: #Phoenix.LiveView.Socket<id: "phx-F_1MH_6F0ciqVqwi", endpoint: VyasaWeb.Endpoint, view: VyasaWeb.ModeLive.Mediator, parent_pid: nil, root_pid: #PID<0.8416.0>, router: VyasaWeb.Router, assigns: %{mode: %VyasaWeb.ModeLive.UserMode{mode: "read", default_ui_state: %VyasaWeb.ModeLive.UiState{show_media_bridge?: true, show_action_bar?: true}, mode_icon_name: "hero-book-open", quick_actions: [:mark_quote, :bookmark], control_panel_modes: ["discuss"], mode_actions: [:mark_quote, :bookmark], action_bar_actions: [:nav_back, :nav_fwd], action_bar_info_types: nil, action_bar_component: VyasaWeb.MediaLive.MediaBridge, action_bar_component_selector: "media-bridge", control_panel_component: VyasaWeb.ControlPanel, control_panel_component_selector: "control-panel", mode_context_component: VyasaWeb.Context.Read, mode_context_component_selector: "read"}, session: %VyasaWeb.Session{name: "ritesh kumar", id: "IhrQV0ypqg8bHakbvb2bymNF", active: true, sangh: %Vyasa.Sangh.Session{__meta__: #Ecto.Schema.Metadata<:loaded, "sessions">, id: "164eb05d-221a-4939-b180-8394e1a5515f", sheafs: #Ecto.Association.NotLoaded<association :sheafs is not loaded>, inserted_at: ~U[2024-09-27 00:51:48Z], updated_at: ~U[2024-09-27 00:51:48Z]}, last_opened: "2024-09-23T11:03:32.022987Z"}, __changed__: %{}, flash: %{}, locale: "en-GB", url_params: %{"chap_no" => "1", "source_title" => "hanuman_chalisa"}, live_action: :show_verses, ui_state: %VyasaWeb.ModeLive.UiState{show_media_bridge?: true, show_action_bar?: true}, device_type: :desktop, tz: %{timezone: "Asia/Singapore", timezone_offset: 480}}, transport_pid: #PID<0.8403.0>, ...>, components: {%{15 => {VyasaWeb.Context.Read.VerseMatrix, "verse-aa3ad88b-0de1-443e-b471-c08a44e67c61", %{id: "verse-aa3ad88b-0de1-443e-b471-c08a44e67c61", edge: [%{title: "1.10", field: [:body], verseup: {:big, "dn"}}, %{node: %Vyasa.Written.Translation{__meta__: #Ecto.Schema.Metadata<:loaded, "translations">, id: "651676b6-ffc3-41c1-b525-f376989f639e", lang: "en", type: "verses", target: %Vyasa.Written.Translation.Target{id: "dd20a94f-8f34-49f8-8da8-4321cfecf172", title: nil, title_translit: nil, body: "प्रभु चरित्र सुनिबे को रसिया ।\n\nराम लखन सीता मन बसिया ॥८॥", body_meant: nil, body_translit: "prabhu caritra sunibe ko rasiyā .\n\nrāma lakhana sītā mana basiyā ..8..", body_translit_meant: "You feel extremely delighted in listening to Lord Rama’s doings and conduct. Lord Rama, Mother Sita, and Lord Laxmana dwell forever in your heart."}, verse_id: "aa3ad88b-0de1-443e-b471-c08a44e67c61", verse: #Ecto.Association.NotLoaded<association :verse is not loaded>, chapter_no: nil, chapter: #Ecto.Association.NotLoaded<association :chapter is not loaded>, source_id: "63918acd-77a9-451a-b8d1-8d5b73208eae", source: #Ecto.Association.NotLoaded<association :source is not loaded>}, field: [:target, :body_translit], verseup: :mid}, %{node: %Vyasa.Written.Translation{__meta__: #Ecto.Schema.Metadata<:loaded, "translations">, id: "651676b6-ffc3-41c1-b525-f376989f639e", lang: "en", type: "verses", target: %Vyasa.Written.Translation.Target{id: "dd20a94f-8f34-49f8-8da8-4321cfecf172", title: nil, title_translit: nil, body: "प्रभु चरित्र सुनिबे को रसिया ।\n\nराम लखन सीता मन बसिया ॥८॥", body_meant: nil, body_translit: "prabhu caritra sunibe ko rasiyā .\n\nrāma lakhana sītā mana basiyā ..8..", body_translit_meant: "You feel extremely delighted in listening to Lord Rama’s doings and conduct. Lord Rama, Mother Sita, and Lord Laxmana dwell forever in your heart."}, verse_id: "aa3ad88b-0de1-443e-b471-c08a44e67c61", verse: #Ecto.Association.NotLoaded<association :verse is not loaded>, chapter_no: nil, chapter: #Ecto.Association.NotLoaded<association :chapter is not loaded>, source_id: "63918acd-77a9-451a-b8d1-8d5b73208eae", source: #Ecto.Association.NotLoaded<association :source is not loaded>}, field: [:target, :body_translit_meant], verseup: :mid}, %{node: %Vyasa.Written.Translation{__meta__: #Ecto.Schema.Metadata<:loaded, "translations">, id: "651676b6-ffc3-41c1-b525-f376989f639e", lang: "en", type: "verses", target: %Vyasa.Written.Translation.Target{id: "dd20a94f-8f34-49f8-8da8-4321cfecf172", title: nil, title_translit: nil, body: "प्रभु चरित्र सुनिबे को रसिया ।\n\nराम लखन सीता मन बसिया ॥८॥", body_meant: nil, body_translit: "prabhu caritra sunibe ko rasiyā .\n\nrāma lakhana sītā mana basiyā ..8..", body_translit_meant: "You feel extremely delighted in listening to Lord Rama’s doings and conduct. Lord Rama, Mother Sita, and Lord Laxmana dwell forever in your heart."}, verse_id: "aa3ad88b-0de1-443e-b471-c08a44e67c61", verse: #Ecto.Association.NotLoaded<association :verse is not loaded>, chapter_no: nil, chapter: #Ecto.Association.NotLoaded<association :chapter is not loaded>, source_id: "63918acd-77a9-451a-b8d1-8d5b73208eae", source: #Ecto.Association.NotLoaded<association :source is not loaded>}, field: [:target, :body], verseup: :mid}], __changed__: %{}, flash: %{}, marks: [%Vyasa.Sangh.Mark{__meta__: #Ecto.Schema.Metadata<:loaded, "marks">, id: "5dfdb167-6c57-46dd-a0c4-10b52cb03a85", body: "wonderful", order: 2, state: :live, verse_id: nil, sheaf_id: "7f4ab16b-0caf-4009-ba2a-3ddded81d9aa", sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>, binding_id: "001da594-3808-46cf-9b9c-5dfb3559780e", binding: %Vyasa.Adapters.Binding{__meta__: #Ecto.Schema.Metadata<:loaded, "bindings">, id: "001da594-3808-46cf-9b9c-5dfb3559780e", w_type: nil, field_key: ["target", "body_translit_meant"], node_id: nil, verse_id: nil, verse: #Ecto.Association.NotLoaded<association :verse is not loaded>, chapter_no: nil, chapter: #Ecto.Association.NotLoaded<association :chapter is not loaded>, source_id: nil, source: #Ecto.Association.NotLoaded<association :source is not loaded>, translation_id: "97a7a662-a91b-486f-93e8-7ae932d01a1a", translation: #Ecto.Association.NotLoaded<association :translation is not loaded>, sheaf_id: nil, sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>, window: nil}, inserted_at: ~U[2024-10-11 04:31:50Z], updated_at: ~U[2024-10-11 04:31:50Z]}, %Vyasa.Sangh.Mark{__meta__: #Ecto.Schema.Metadata<:loaded, "marks">, id: "273a093d-4f90-40a4-b19a-2f8f7825d201", body: "truncated utc datetime", order: 1, state: :live, verse_id: nil, sheaf_id: "7f4ab16b-0caf-4009-ba2a-3ddded81d9aa", sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>, binding_id: "ef39315b-530c-4841-ba32-86773f451727", binding: %Vyasa.Adapt (truncated)
[debug] MOUNT VyasaWeb.ModeLive.Mediator
  Parameters: %{"chap_no" => "1", "source_title" => "hanuman_chalisa"}
  Session: %{"_csrf_token" => "DJ-RIoXwEzHW82rbb21le_8k"}
[debug] QUERY OK source="sessions" db=3.5ms idle=1690.4ms
SELECT s0."id", s0."inserted_at", s0."updated_at" FROM "sessions" AS s0 WHERE (s0."id" = $1) ["164eb05d-221a-4939-b180-8394e1a5515f"]
↳

* Fix duplicate id issue on verse matrix

* Standardise use of @event_target, cleanups

When using @event_target, the intent is that phx-target values
will be passed around. This must be agnostic to the 2 main ways of
supplying that argument, as a HTML selector, or as a module name (or @myself).
Therefore, we should discourage ourselves from doing format-strings at
the point of the @event_target being supplied as an argument, meaning:

good, because agnostic:
phx-target={@event_target}

bad, because hardcoded:
phx-target={"#" <> @event_target}
* in this case, the event trigger will throw a dom error.

* [Attempt]: Sanitise, defrag orders in marks-list

If this is an anti-pattern, then this commit should be reverted.

* UI fixes: hide buttons on marks when !is_editable?

* Add in stub event handlers to prevent crashes

Temporary stuff, will be addressed in immediate-next PR

* Minor changes

* Toggle edit state for marks content

* Partial implementation of edit marks

the form stuff doesn't exist so it's not wired up yet. To be frank,
im' not sure how to set up a form without it needing to hold state.

* [BUGGY] Wire up form update for edit

this does the following:
1. wires up the form like how we usedd it in createMark
2. actually captures the event properly within the event handler,
everything looks good at that point, even the edit_mark_in_marks
function on inspection looks good
3. the marks is getting assigned to properly because the newly edited
mark content is seen after doing a dom refresh
4. HOWEVER, the print statement at the sheaf_update function DOES NOT
show the correct, updated marks in the sheaf

here's a dump for it for reference

[debug] HANDLE EVENT "editMarkContent" in VyasaWeb.ModeLive.Mediator
  Component: VyasaWeb.Context.Read
  Parameters: %{"mark_id" => "02218551-591f-4450-abbd-a7b7d76fd48e"}
[debug] Replied in 2ms
[debug] HANDLE EVENT "editMarkContent" in VyasaWeb.ModeLive.Mediator
  Component: VyasaWeb.Context.Read
  Parameters: %{"mark_body" => "  testing\n\n\nwhat hte heck", "mark_id" => "02218551-591f-4450-abbd-a7b7d76fd48e"}
>>> UPDATE SHEAF -- SHOULD BE WRITING TO DB NOW: %Vyasa.Sangh.Sheaf{
  __meta__: #Ecto.Schema.Metadata<:loaded, "sheafs">,
  id: "7f4ab16b-0caf-4009-ba2a-3ddded81d9aa",
  body: nil,
  active: true,
  path: %EctoLtree.LabelTree{labels: ["7f4ab16b"]},
  signature: nil,
  traits: ["draft"],
  child_count: 0,
  session_id: "164eb05d-221a-4939-b180-8394e1a5515f",
  session: #Ecto.Association.NotLoaded<association :session is not loaded>,
  parent_id: nil,
  parent: #Ecto.Association.NotLoaded<association :parent is not loaded>,
  marks: [
    %Vyasa.Sangh.Mark{
      __meta__: #Ecto.Schema.Metadata<:loaded, "marks">,
      id: "555eb625-e392-496e-9831-4f4c130be6fd",
      body: "wonderful stuff",
      order: 5,
      state: :live,
      verse_id: nil,
      sheaf_id: "7f4ab16b-0caf-4009-ba2a-3ddded81d9aa",
      sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>,
      binding_id: "072124d0-5e27-4601-832f-35eaa6426879",
      binding: %Vyasa.Adapters.Binding{
        __meta__: #Ecto.Schema.Metadata<:loaded, "bindings">,
        id: "072124d0-5e27-4601-832f-35eaa6426879",
        w_type: nil,
        field_key: ["target", "body_translit_meant"],
        node_id: nil,
        verse_id: nil,
        verse: #Ecto.Association.NotLoaded<association :verse is not loaded>,
        chapter_no: nil,
        chapter: #Ecto.Association.NotLoaded<association :chapter is not loaded>,
        source_id: nil,
        source: #Ecto.Association.NotLoaded<association :source is not loaded>,
        translation_id: "97a7a662-a91b-486f-93e8-7ae932d01a1a",
        translation: #Ecto.Association.NotLoaded<association :translation is not loaded>,
        sheaf_id: nil,
        sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>,
        window: nil
      },
      inserted_at: ~U[2024-10-12 08:46:54Z],
      updated_at: ~U[2024-10-12 08:46:54Z]
    },
    %Vyasa.Sangh.Mark{
      __meta__: #Ecto.Schema.Metadata<:loaded, "marks">,
      id: "b22a5661-8268-4875-be26-a12256414136",
      body: nil,
      order: 5,
      state: :draft,
      verse_id: nil,
      sheaf_id: "7f4ab16b-0caf-4009-ba2a-3ddded81d9aa",
      sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>,
      binding_id: "90e18044-73b2-4ede-a149-a381de893b9f",
      binding: %Vyasa.Adapters.Binding{
        __meta__: #Ecto.Schema.Metadata<:loaded, "bindings">,
        id: "90e18044-73b2-4ede-a149-a381de893b9f",
        w_type: nil,
        field_key: ["target", "body_translit_meant"],
        node_id: nil,
        verse_id: nil,
        verse: #Ecto.Association.NotLoaded<association :verse is not loaded>,
        chapter_no: nil,
        chapter: #Ecto.Association.NotLoaded<association :chapter is not loaded>,
        source_id: nil,
        source: #Ecto.Association.NotLoaded<association :source is not loaded>,
        translation_id: "fc80709a-39dc-4b9c-95c3-1d64ce818302",
        translation: #Ecto.Association.NotLoaded<association :translation is not loaded>,
        sheaf_id: nil,
        sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>,
        window: nil
      },
      inserted_at: ~U[2024-10-12 09:52:40Z],
      updated_at: ~U[2024-10-12 09:52:40Z]
    },
    %Vyasa.Sangh.Mark{
      __meta__: #Ecto.Schema.Metadata<:loaded, "marks">,
      id: "8af43833-575c-4eb8-83b1-eb4e58509e4c",
      body: nil,
      order: 4,
      state: :draft,
      verse_id: nil,
      sheaf_id: "7f4ab16b-0caf-4009-ba2a-3ddded81d9aa",
      sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>,
      binding_id: "23b70937-ed81-47fe-a560-ee14287bff7d",
      binding: %Vyasa.Adapters.Binding{
        __meta__: #Ecto.Schema.Metadata<:loaded, "bindings">,
        id: "23b70937-ed81-47fe-a560-ee14287bff7d",
        w_type: nil,
        field_key: ["target", "body_translit_meant"],
        node_id: nil,
        verse_id: nil,
        verse: #Ecto.Association.NotLoaded<association :verse is not loaded>,
        chapter_no: nil,
        chapter: #Ecto.Association.NotLoaded<association :chapter is not loaded>,
        source_id: nil,
        source: #Ecto.Association.NotLoaded<association :source is not loaded>,
        translation_id: "97a7a662-a91b-486f-93e8-7ae932d01a1a",
        translation: #Ecto.Association.NotLoaded<association :translation is not loaded>,
        sheaf_id: nil,
        sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>,
        window: nil
      },
      inserted_at: ~U[2024-10-12 09:46:13Z],
      updated_at: ~U[2024-10-12 09:46:13Z]
    },
    %Vyasa.Sangh.Mark{
      __meta__: #Ecto.Schema.Metadata<:loaded, "marks">,
      id: "c7ad47e6-629d-4382-936d-64d757772c4e",
      body: nil,
      order: 3,
      state: :draft,
      verse_id: nil,
      sheaf_id: "7f4ab16b-0caf-4009-ba2a-3ddded81d9aa",
      sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>,
      binding_id: "d5758230-7966-4f9b-8c16-ae13998cd71b",
      binding: %Vyasa.Adapters.Binding{
        __meta__: #Ecto.Schema.Metadata<:loaded, "bindings">,
        id: "d5758230-7966-4f9b-8c16-ae13998cd71b",
        w_type: nil,
        field_key: ["target", "body_translit_meant"],
        node_id: nil,
        verse_id: nil,
        verse: #Ecto.Association.NotLoaded<association :verse is not loaded>,
        chapter_no: nil,
        chapter: #Ecto.Association.NotLoaded<association :chapter is not loaded>,
        source_id: nil,
        source: #Ecto.Association.NotLoaded<association :source is not loaded>,
        translation_id: "fc80709a-39dc-4b9c-95c3-1d64ce818302",
        translation: #Ecto.Association.NotLoaded<association :translation is not loaded>,
        sheaf_id: nil,
        sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>,
        window: nil
      },
      inserted_at: ~U[2024-10-12 09:44:09Z],
      updated_at: ~U[2024-10-12 09:44:09Z]
    },
    %Vyasa.Sangh.Mark{
      __meta__: #Ecto.Schema.Metadata<:loaded, "marks">,
      id: "02218551-591f-4450-abbd-a7b7d76fd48e",
      body: "testing",
      order: 2,
      state: :live,
      verse_id: nil,
      sheaf_id: "7f4ab16b-0caf-4009-ba2a-3ddded81d9aa",
      sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>,
      binding_id: "19ffdc82-a5d8-49c3-8b01-1559736dad80",
      binding: %Vyasa.Adapters.Binding{
        __meta__: #Ecto.Schema.Metadata<:loaded, "bindings">,
        id: "19ffdc82-a5d8-49c3-8b01-1559736dad80",
        w_type: nil,
        field_key: ["target", "body_translit_meant"],
        node_id: nil,
        verse_id: nil,
        verse: #Ecto.Association.NotLoaded<association :verse is not loaded>,
        chapter_no: nil,
        chapter: #Ecto.Association.NotLoaded<association :chapter is not loaded>,
        source_id: nil,
        source: #Ecto.Association.NotLoaded<association :source is not loaded>,
        translation_id: "fc80709a-39dc-4b9c-95c3-1d64ce818302",
        translation: #Ecto.Association.NotLoaded<association :translation is not loaded>,
        sheaf_id: nil,
        sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>,
        window: nil
      },
      inserted_at: ~U[2024-10-12 09:43:19Z],
      updated_at: ~U[2024-10-12 09:43:19Z]
    },
    %Vyasa.Sangh.Mark{
      __meta__: #Ecto.Schema.Metadata<:loaded, "marks">,
      id: "90c6036a-9bd1-4b65-82d5-f121ec4d7867",
      body: nil,
      order: 2,
      state: :draft,
      verse_id: nil,
      sheaf_id: "7f4ab16b-0caf-4009-ba2a-3ddded81d9aa",
      sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>,
      binding_id: "b92f990d-99a2-4f04-a2d4-d1135021ee8c",
      binding: %Vyasa.Adapters.Binding{
        __meta__: #Ecto.Schema.Metadata<:loaded, "bindings">,
        id: "b92f990d-99a2-4f04-a2d4-d1135021ee8c",
        w_type: nil,
        field_key: ["target", "body_translit_meant"],
        node_id: nil,
        verse_id: nil,
        verse: #Ecto.Association.NotLoaded<association :verse is not loaded>,
        chapter_no: nil,
        chapter: #Ecto.Association.NotLoaded<association :chapter is not loaded>,
        source_id: nil,
        source: #Ecto.Association.NotLoaded<association :source is not loaded>,
        translation_id: "97a7a662-a91b-486f-93e8-7ae932d01a1a",
        translation: #Ecto.Association.NotLoaded<association :translation is not loaded>,
        sheaf_id: nil,
        sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>,
        window: nil
      },
      inserted_at: ~U[2024-10-11 09:03:00Z],
      updated_at: ~U[2024-10-11 09:03:00Z]
    }
  ],
  inserted_at: ~N[2024-09-27 00:51:48],
  updated_at: ~N[2024-09-27 00:51:48]
}
[debug] Replied in 81ms
[debug] HANDLE EVENT "verses::focus_toggle_on_quick_mark_drafting" in VyasaWeb.ModeLive.Mediator
  Component: VyasaWeb.Context.Read
  Parameters: %{"is_focusing?" => false, "value" => ""}
[debug] Replied in 129µs
iex([email protected])17>

* marks order force

* old man mark is not feeling so good

* ReWrite how marks get initialised @ :show_verse (#119)

* Minor change in fn signature

* Add init_draft_reflector()

* Don't rely on the time async message passing

* Use custom generic_modal_wrapper

This one has more specific callback attributes and tailwind classes can
be injected to it.

* Create data and ui skeletons for sheaf_creator

* Add support for human friendly time formatting

* Setup skeleton for replyto context

Some pending todo functions for how the reply to context shall be determined

* Standardise UI, improve wrapper's default UI

* Improve generic_modal_wrapper styling slots

* Wire sheaf creation form to stubbed event handler

Relevant TODOs have been added

* Use session.name for signature, add handler stubs

* Edit marks in read mode (#118)

* Add generic debug dump component

This makes life easy when wiring things up

* Rename namespace for Context.Read.*

* Groundwork: add discuss component w sheafs

* Init Context.Components mod for common components

* Add skeletons for Sheaf Container

Container managers sheaf state within itself.
Should actually make the verse-matrix use this container, sometime.

* Minor changes, add some TODOs to share

explicit todos

Minor change

* Add live component EditableMarkDisplay

* Add UI improvements to EditableMarkDisplay

The edit button on quick draft should only be seen when the dropdown is
expanded and all the marks can be seen. The general pattern I'm trying
to follow is that buttons should only be shown when an action makes
sense. So here, if the user can't even see the marks currently
accumulating, then the user shouldn't have the chance to edit any marks.

Notice that the EditableMarkDisplay is a live_component that is a child
of a function component (collapsible_marks_display). This is so that it can keep its own state and
do it's own event-handling. I'm not sure if this is pattern-breaking.
A reference to the actual parent live_component that calls collapsible_marks_display
will always be there in case there's a need for the parent to handle
any particular events. So comms b/w live_components is still going to be
via phx-target values.

* Change <input/> -> <textarea/> fr quick_draft_form

* Add tailwind config for custom svg icons

not sure how the scaling for this works, seems like i can't just put in
the class="h-5 w-5" to do the scaling

* Let custom svg be scalable

* Subtly shift the ping indicator to control panel

* Marks ordering in Sheaf and L-Trees  (#114)

* do sheafs grow on trees

* sangh session dealing with lineage

* Solve initial order problem

* fix: ensure non-null id used @ EditableMarkDisplay

---------

Co-authored-by: ks0m1c_dharma <[email protected]>

* Trigger Diff

* TOMBSTONING

* Fix bugs and revert ui for read_mode:delete marks

1.  JIT generate id for marks yet to be inserted to the db: instead of
    using a temp id, I'm actually assigning a JIT-generated id for a
    mark even if that isn't inserted into the db yet. this has two
    benefits: div ids have meaningful static ids (e.g.
    mark-container-\<\> mark.id) regardless of whether that mark has
    been inserted into the db or not. While doing this, the changeset
    for marks has been udpated to add id as well. This fixes a bunch of
    id-based errors as well.

2.  while doing 1, it came to light that the bindHoverune handlers were
    not handling the draft mark update properly (i.e. not using the
    already existing update function in mark) . it's changed now,
    example of the diff:

    ``` diff
      @impl true
      def handle_event(
            "bindHoveRune",
            %{"binding" => bind = %{"verse_id" => verse_id}},
            %{
              assigns: %{
                kv_verses: verses,
                marks: [%Mark{state: :draft, verse_id: curr_verse_id} = d_mark | marks]
              }
            } = socket
          )
          when is_binary(curr_verse_id) and verse_id != curr_verse_id do
        # binding here blocks the stream from appending to quote
        bind = Draft.bind_node(bind)

        bound_verses =
          verses
           |> then(&put_in(&1[verse_id].binding, bind))
           |> then(&put_in(&1[curr_verse_id].binding, nil))

    +    updated_draft_mark = d_mark |> Mark.update_mark(%{binding: bind, verse_id: verse_id})
    +
         {:noreply,
          socket
          |> mutate_verses(curr_verse_id, bound_verses)
          |> mutate_verses(verse_id, bound_verses)
    -     |> assign(:marks, [%{d_mark | binding: bind, verse_id: verse_id} | marks])}
    +     |> assign(:marks, [updated_draft_mark | marks])}
       end
    ```

3.  add ui state structs: all of the relevant ui states have structs
    that are intended to be static interfaces. this felt better than
    directly keeping state within various sockets and is done with a
    view to remove live components and change them to function
    components wherever possible.

4.  bugfix for `order()`:

    - it had an off-by-one-error
    - shifted it to Vyasa.Sangh.Mark
    - also note that the order shall be 1-indexed instead of 0-indexed
      for human-friendliness

5.  minor fixes:

    1.  fix update<sub>mark</sub> default argument

        ``` diff
        -def update_mark(%Mark{} = draft_mark, opts \\ []) do
        +def update_mark(%Mark{} = draft_mark, opts \\ %{}) do
        ```

1.  In this commit, the marks<sub>ui</sub> is NOT kept by the read
    context module, that's why when I update things by create mark or
    delete mark, the ui state is not preserved and initial, default
    state is seen. This was intentionally done in this commit because
    I'm having problems with duplicate ids for verses for some reason,
    I'll show it in the next commit, so that the problem can be clearly
    seen.

* [BUGGY] keep marks_ui within ReadContext

This is buggy, not sure why there's a duplicate yet.  will come back to
it after lunch

Replication Steps:
1. delete all marks and see there's no error
2. create first mark ==> no error
3. create second mark ==> crashes due to duplicate verse id

Crash dump:

[debug] Replied in 13ms
[error] GenServer #PID<0.8416.0> terminating
** (RuntimeError) found duplicate ID "verse-7d9d588a-34fc-4f19-b974-fc32b49b6a61" for component VyasaWeb.Context.Read.VerseMatrix when rendering template
    (phoenix_live_view 1.0.0-rc.6) lib/phoenix_live_view/diff.ex:634: anonymous fn/5 in Phoenix.LiveView.Diff.render_pending_components/6
    (elixir 1.17.2) lib/enum.ex:2531: Enum."-reduce/3-lists^foldl/2-0-"/3
    (phoenix_live_view 1.0.0-rc.6) lib/phoenix_live_view/diff.ex:631: anonymous fn/4 in Phoenix.LiveView.Diff.render_pending_components/6
    (stdlib 5.2.3) maps.erl:416: :maps.fold_1/4
    (phoenix_live_view 1.0.0-rc.6) lib/phoenix_live_view/diff.ex:625: Phoenix.LiveView.Diff.render_pending_components/6
    (phoenix_live_view 1.0.0-rc.6) lib/phoenix_live_view/diff.ex:217: Phoenix.LiveView.Diff.write_component/4
    (phoenix_live_view 1.0.0-rc.6) lib/phoenix_live_view/channel.ex:662: Phoenix.LiveView.Channel.component_handle/4
    (stdlib 5.2.3) gen_server.erl:1095: :gen_server.try_handle_info/3
    (stdlib 5.2.3) gen_server.erl:1183: :gen_server.handle_msg/6
    (stdlib 5.2.3) proc_lib.erl:251: :proc_lib.wake_up/3
Last message: %Phoenix.Socket.Message{topic: "lv:phx-F_1MH_6F0ciqVqwi", event: "event", payload: %{"cid" => 3, "event" => "createMark", "type" => "form", "value" => "body=how+about+now%2C+any+duplicate%3F"}, ref: "23", join_ref: "4"}
State: %{socket: #Phoenix.LiveView.Socket<id: "phx-F_1MH_6F0ciqVqwi", endpoint: VyasaWeb.Endpoint, view: VyasaWeb.ModeLive.Mediator, parent_pid: nil, root_pid: #PID<0.8416.0>, router: VyasaWeb.Router, assigns: %{mode: %VyasaWeb.ModeLive.UserMode{mode: "read", default_ui_state: %VyasaWeb.ModeLive.UiState{show_media_bridge?: true, show_action_bar?: true}, mode_icon_name: "hero-book-open", quick_actions: [:mark_quote, :bookmark], control_panel_modes: ["discuss"], mode_actions: [:mark_quote, :bookmark], action_bar_actions: [:nav_back, :nav_fwd], action_bar_info_types: nil, action_bar_component: VyasaWeb.MediaLive.MediaBridge, action_bar_component_selector: "media-bridge", control_panel_component: VyasaWeb.ControlPanel, control_panel_component_selector: "control-panel", mode_context_component: VyasaWeb.Context.Read, mode_context_component_selector: "read"}, session: %VyasaWeb.Session{name: "ritesh kumar", id: "IhrQV0ypqg8bHakbvb2bymNF", active: true, sangh: %Vyasa.Sangh.Session{__meta__: #Ecto.Schema.Metadata<:loaded, "sessions">, id: "164eb05d-221a-4939-b180-8394e1a5515f", sheafs: #Ecto.Association.NotLoaded<association :sheafs is not loaded>, inserted_at: ~U[2024-09-27 00:51:48Z], updated_at: ~U[2024-09-27 00:51:48Z]}, last_opened: "2024-09-23T11:03:32.022987Z"}, __changed__: %{}, flash: %{}, locale: "en-GB", url_params: %{"chap_no" => "1", "source_title" => "hanuman_chalisa"}, live_action: :show_verses, ui_state: %VyasaWeb.ModeLive.UiState{show_media_bridge?: true, show_action_bar?: true}, device_type: :desktop, tz: %{timezone: "Asia/Singapore", timezone_offset: 480}}, transport_pid: #PID<0.8403.0>, ...>, components: {%{15 => {VyasaWeb.Context.Read.VerseMatrix, "verse-aa3ad88b-0de1-443e-b471-c08a44e67c61", %{id: "verse-aa3ad88b-0de1-443e-b471-c08a44e67c61", edge: [%{title: "1.10", field: [:body], verseup: {:big, "dn"}}, %{node: %Vyasa.Written.Translation{__meta__: #Ecto.Schema.Metadata<:loaded, "translations">, id: "651676b6-ffc3-41c1-b525-f376989f639e", lang: "en", type: "verses", target: %Vyasa.Written.Translation.Target{id: "dd20a94f-8f34-49f8-8da8-4321cfecf172", title: nil, title_translit: nil, body: "प्रभु चरित्र सुनिबे को रसिया ।\n\nराम लखन सीता मन बसिया ॥८॥", body_meant: nil, body_translit: "prabhu caritra sunibe ko rasiyā .\n\nrāma lakhana sītā mana basiyā ..8..", body_translit_meant: "You feel extremely delighted in listening to Lord Rama’s doings and conduct. Lord Rama, Mother Sita, and Lord Laxmana dwell forever in your heart."}, verse_id: "aa3ad88b-0de1-443e-b471-c08a44e67c61", verse: #Ecto.Association.NotLoaded<association :verse is not loaded>, chapter_no: nil, chapter: #Ecto.Association.NotLoaded<association :chapter is not loaded>, source_id: "63918acd-77a9-451a-b8d1-8d5b73208eae", source: #Ecto.Association.NotLoaded<association :source is not loaded>}, field: [:target, :body_translit], verseup: :mid}, %{node: %Vyasa.Written.Translation{__meta__: #Ecto.Schema.Metadata<:loaded, "translations">, id: "651676b6-ffc3-41c1-b525-f376989f639e", lang: "en", type: "verses", target: %Vyasa.Written.Translation.Target{id: "dd20a94f-8f34-49f8-8da8-4321cfecf172", title: nil, title_translit: nil, body: "प्रभु चरित्र सुनिबे को रसिया ।\n\nराम लखन सीता मन बसिया ॥८॥", body_meant: nil, body_translit: "prabhu caritra sunibe ko rasiyā .\n\nrāma lakhana sītā mana basiyā ..8..", body_translit_meant: "You feel extremely delighted in listening to Lord Rama’s doings and conduct. Lord Rama, Mother Sita, and Lord Laxmana dwell forever in your heart."}, verse_id: "aa3ad88b-0de1-443e-b471-c08a44e67c61", verse: #Ecto.Association.NotLoaded<association :verse is not loaded>, chapter_no: nil, chapter: #Ecto.Association.NotLoaded<association :chapter is not loaded>, source_id: "63918acd-77a9-451a-b8d1-8d5b73208eae", source: #Ecto.Association.NotLoaded<association :source is not loaded>}, field: [:target, :body_translit_meant], verseup: :mid}, %{node: %Vyasa.Written.Translation{__meta__: #Ecto.Schema.Metadata<:loaded, "translations">, id: "651676b6-ffc3-41c1-b525-f376989f639e", lang: "en", type: "verses", target: %Vyasa.Written.Translation.Target{id: "dd20a94f-8f34-49f8-8da8-4321cfecf172", title: nil, title_translit: nil, body: "प्रभु चरित्र सुनिबे को रसिया ।\n\nराम लखन सीता मन बसिया ॥८॥", body_meant: nil, body_translit: "prabhu caritra sunibe ko rasiyā .\n\nrāma lakhana sītā mana basiyā ..8..", body_translit_meant: "You feel extremely delighted in listening to Lord Rama’s doings and conduct. Lord Rama, Mother Sita, and Lord Laxmana dwell forever in your heart."}, verse_id: "aa3ad88b-0de1-443e-b471-c08a44e67c61", verse: #Ecto.Association.NotLoaded<association :verse is not loaded>, chapter_no: nil, chapter: #Ecto.Association.NotLoaded<association :chapter is not loaded>, source_id: "63918acd-77a9-451a-b8d1-8d5b73208eae", source: #Ecto.Association.NotLoaded<association :source is not loaded>}, field: [:target, :body], verseup: :mid}], __changed__: %{}, flash: %{}, marks: [%Vyasa.Sangh.Mark{__meta__: #Ecto.Schema.Metadata<:loaded, "marks">, id: "5dfdb167-6c57-46dd-a0c4-10b52cb03a85", body: "wonderful", order: 2, state: :live, verse_id: nil, sheaf_id: "7f4ab16b-0caf-4009-ba2a-3ddded81d9aa", sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>, binding_id: "001da594-3808-46cf-9b9c-5dfb3559780e", binding: %Vyasa.Adapters.Binding{__meta__: #Ecto.Schema.Metadata<:loaded, "bindings">, id: "001da594-3808-46cf-9b9c-5dfb3559780e", w_type: nil, field_key: ["target", "body_translit_meant"], node_id: nil, verse_id: nil, verse: #Ecto.Association.NotLoaded<association :verse is not loaded>, chapter_no: nil, chapter: #Ecto.Association.NotLoaded<association :chapter is not loaded>, source_id: nil, source: #Ecto.Association.NotLoaded<association :source is not loaded>, translation_id: "97a7a662-a91b-486f-93e8-7ae932d01a1a", translation: #Ecto.Association.NotLoaded<association :translation is not loaded>, sheaf_id: nil, sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>, window: nil}, inserted_at: ~U[2024-10-11 04:31:50Z], updated_at: ~U[2024-10-11 04:31:50Z]}, %Vyasa.Sangh.Mark{__meta__: #Ecto.Schema.Metadata<:loaded, "marks">, id: "273a093d-4f90-40a4-b19a-2f8f7825d201", body: "truncated utc datetime", order: 1, state: :live, verse_id: nil, sheaf_id: "7f4ab16b-0caf-4009-ba2a-3ddded81d9aa", sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>, binding_id: "ef39315b-530c-4841-ba32-86773f451727", binding: %Vyasa.Adapt (truncated)
[debug] MOUNT VyasaWeb.ModeLive.Mediator
  Parameters: %{"chap_no" => "1", "source_title" => "hanuman_chalisa"}
  Session: %{"_csrf_token" => "DJ-RIoXwEzHW82rbb21le_8k"}
[debug] QUERY OK source="sessions" db=3.5ms idle=1690.4ms
SELECT s0."id", s0."inserted_at", s0."updated_at" FROM "sessions" AS s0 WHERE (s0."id" = $1) ["164eb05d-221a-4939-b180-8394e1a5515f"]
↳

* Fix duplicate id issue on verse matrix

* Standardise use of @event_target, cleanups

When using @event_target, the intent is that phx-target values
will be passed around. This must be agnostic to the 2 main ways of
supplying that argument, as a HTML selector, or as a module name (or @myself).
Therefore, we should discourage ourselves from doing format-strings at
the point of the @event_target being supplied as an argument, meaning:

good, because agnostic:
phx-target={@event_target}

bad, because hardcoded:
phx-target={"#" <> @event_target}
* in this case, the event trigger will throw a dom error.

* [Attempt]: Sanitise, defrag orders in marks-list

If this is an anti-pattern, then this commit should be reverted.

* UI fixes: hide buttons on marks when !is_editable?

* Add in stub event handlers to prevent crashes

Temporary stuff, will be addressed in immediate-next PR

* Minor changes

* Toggle edit state for marks content

* Partial implementation of edit marks

the form stuff doesn't exist so it's not wired up yet. To be frank,
im' not sure how to set up a form without it needing to hold state.

* [BUGGY] Wire up form update for edit

this does the following:
1. wires up the form like how we usedd it in createMark
2. actually captures the event properly within the event handler,
everything looks good at that point, even the edit_mark_in_marks
function on inspection looks good
3. the marks is getting assigned to properly because the newly edited
mark content is seen after doing a dom refresh
4. HOWEVER, the print statement at the sheaf_update function DOES NOT
show the correct, updated marks in the sheaf

here's a dump for it for reference

[debug] HANDLE EVENT "editMarkContent" in VyasaWeb.ModeLive.Mediator
  Component: VyasaWeb.Context.Read
  Parameters: %{"mark_id" => "02218551-591f-4450-abbd-a7b7d76fd48e"}
[debug] Replied in 2ms
[debug] HANDLE EVENT "editMarkContent" in VyasaWeb.ModeLive.Mediator
  Component: VyasaWeb.Context.Read
  Parameters: %{"mark_body" => "  testing\n\n\nwhat hte heck", "mark_id" => "02218551-591f-4450-abbd-a7b7d76fd48e"}
>>> UPDATE SHEAF -- SHOULD BE WRITING TO DB NOW: %Vyasa.Sangh.Sheaf{
  __meta__: #Ecto.Schema.Metadata<:loaded, "sheafs">,
  id: "7f4ab16b-0caf-4009-ba2a-3ddded81d9aa",
  body: nil,
  active: true,
  path: %EctoLtree.LabelTree{labels: ["7f4ab16b"]},
  signature: nil,
  traits: ["draft"],
  child_count: 0,
  session_id: "164eb05d-221a-4939-b180-8394e1a5515f",
  session: #Ecto.Association.NotLoaded<association :session is not loaded>,
  parent_id: nil,
  parent: #Ecto.Association.NotLoaded<association :parent is not loaded>,
  marks: [
    %Vyasa.Sangh.Mark{
      __meta__: #Ecto.Schema.Metadata<:loaded, "marks">,
      id: "555eb625-e392-496e-9831-4f4c130be6fd",
      body: "wonderful stuff",
      order: 5,
      state: :live,
      verse_id: nil,
      sheaf_id: "7f4ab16b-0caf-4009-ba2a-3ddded81d9aa",
      sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>,
      binding_id: "072124d0-5e27-4601-832f-35eaa6426879",
      binding: %Vyasa.Adapters.Binding{
        __meta__: #Ecto.Schema.Metadata<:loaded, "bindings">,
        id: "072124d0-5e27-4601-832f-35eaa6426879",
        w_type: nil,
        field_key: ["target", "body_translit_meant"],
        node_id: nil,
        verse_id: nil,
        verse: #Ecto.Association.NotLoaded<association :verse is not loaded>,
        chapter_no: nil,
        chapter: #Ecto.Association.NotLoaded<association :chapter is not loaded>,
        source_id: nil,
        source: #Ecto.Association.NotLoaded<association :source is not loaded>,
        translation_id: "97a7a662-a91b-486f-93e8-7ae932d01a1a",
        translation: #Ecto.Association.NotLoaded<association :translation is not loaded>,
        sheaf_id: nil,
        sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>,
        window: nil
      },
      inserted_at: ~U[2024-10-12 08:46:54Z],
      updated_at: ~U[2024-10-12 08:46:54Z]
    },
    %Vyasa.Sangh.Mark{
      __meta__: #Ecto.Schema.Metadata<:loaded, "marks">,
      id: "b22a5661-8268-4875-be26-a12256414136",
      body: nil,
      order: 5,
      state: :draft,
      verse_id: nil,
      sheaf_id: "7f4ab16b-0caf-4009-ba2a-3ddded81d9aa",
      sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>,
      binding_id: "90e18044-73b2-4ede-a149-a381de893b9f",
      binding: %Vyasa.Adapters.Binding{
        __meta__: #Ecto.Schema.Metadata<:loaded, "bindings">,
        id: "90e18044-73b2-4ede-a149-a381de893b9f",
        w_type: nil,
        field_key: ["target", "body_translit_meant"],
        node_id: nil,
        verse_id: nil,
        verse: #Ecto.Association.NotLoaded<association :verse is not loaded>,
        chapter_no: nil,
        chapter: #Ecto.Association.NotLoaded<association :chapter is not loaded>,
        source_id: nil,
        source: #Ecto.Association.NotLoaded<association :source is not loaded>,
        translation_id: "fc80709a-39dc-4b9c-95c3-1d64ce818302",
        translation: #Ecto.Association.NotLoaded<association :translation is not loaded>,
        sheaf_id: nil,
        sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>,
        window: nil
      },
      inserted_at: ~U[2024-10-12 09:52:40Z],
      updated_at: ~U[2024-10-12 09:52:40Z]
    },
    %Vyasa.Sangh.Mark{
      __meta__: #Ecto.Schema.Metadata<:loaded, "marks">,
      id: "8af43833-575c-4eb8-83b1-eb4e58509e4c",
      body: nil,
      order: 4,
      state: :draft,
      verse_id: nil,
      sheaf_id: "7f4ab16b-0caf-4009-ba2a-3ddded81d9aa",
      sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>,
      binding_id: "23b70937-ed81-47fe-a560-ee14287bff7d",
      binding: %Vyasa.Adapters.Binding{
        __meta__: #Ecto.Schema.Metadata<:loaded, "bindings">,
        id: "23b70937-ed81-47fe-a560-ee14287bff7d",
        w_type: nil,
        field_key: ["target", "body_translit_meant"],
        node_id: nil,
        verse_id: nil,
        verse: #Ecto.Association.NotLoaded<association :verse is not loaded>,
        chapter_no: nil,
        chapter: #Ecto.Association.NotLoaded<association :chapter is not loaded>,
        source_id: nil,
        source: #Ecto.Association.NotLoaded<association :source is not loaded>,
        translation_id: "97a7a662-a91b-486f-93e8-7ae932d01a1a",
        translation: #Ecto.Association.NotLoaded<association :translation is not loaded>,
        sheaf_id: nil,
        sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>,
        window: nil
      },
      inserted_at: ~U[2024-10-12 09:46:13Z],
      updated_at: ~U[2024-10-12 09:46:13Z]
    },
    %Vyasa.Sangh.Mark{
      __meta__: #Ecto.Schema.Metadata<:loaded, "marks">,
      id: "c7ad47e6-629d-4382-936d-64d757772c4e",
      body: nil,
      order: 3,
      state: :draft,
      verse_id: nil,
      sheaf_id: "7f4ab16b-0caf-4009-ba2a-3ddded81d9aa",
      sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>,
      binding_id: "d5758230-7966-4f9b-8c16-ae13998cd71b",
      binding: %Vyasa.Adapters.Binding{
        __meta__: #Ecto.Schema.Metadata<:loaded, "bindings">,
        id: "d5758230-7966-4f9b-8c16-ae13998cd71b",
        w_type: nil,
        field_key: ["target", "body_translit_meant"],
        node_id: nil,
        verse_id: nil,
        verse: #Ecto.Association.NotLoaded<association :verse is not loaded>,
        chapter_no: nil,
        chapter: #Ecto.Association.NotLoaded<association :chapter is not loaded>,
        source_id: nil,
        source: #Ecto.Association.NotLoaded<association :source is not loaded>,
        translation_id: "fc80709a-39dc-4b9c-95c3-1d64ce818302",
        translation: #Ecto.Association.NotLoaded<association :translation is not loaded>,
        sheaf_id: nil,
        sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>,
        window: nil
      },
      inserted_at: ~U[2024-10-12 09:44:09Z],
      updated_at: ~U[2024-10-12 09:44:09Z]
    },
    %Vyasa.Sangh.Mark{
      __meta__: #Ecto.Schema.Metadata<:loaded, "marks">,
      id: "02218551-591f-4450-abbd-a7b7d76fd48e",
      body: "testing",
      order: 2,
      state: :live,
      verse_id: nil,
      sheaf_id: "7f4ab16b-0caf-4009-ba2a-3ddded81d9aa",
      sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>,
      binding_id: "19ffdc82-a5d8-49c3-8b01-1559736dad80",
      binding: %Vyasa.Adapters.Binding{
        __meta__: #Ecto.Schema.Metadata<:loaded, "bindings">,
        id: "19ffdc82-a5d8-49c3-8b01-1559736dad80",
        w_type: nil,
        field_key: ["target", "body_translit_meant"],
        node_id: nil,
        verse_id: nil,
        verse: #Ecto.Association.NotLoaded<association :verse is not loaded>,
        chapter_no: nil,
        chapter: #Ecto.Association.NotLoaded<association :chapter is not loaded>,
        source_id: nil,
        source: #Ecto.Association.NotLoaded<association :source is not loaded>,
        translation_id: "fc80709a-39dc-4b9c-95c3-1d64ce818302",
        translation: #Ecto.Association.NotLoaded<association :translation is not loaded>,
        sheaf_id: nil,
        sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>,
        window: nil
      },
      inserted_at: ~U[2024-10-12 09:43:19Z],
      updated_at: ~U[2024-10-12 09:43:19Z]
    },
    %Vyasa.Sangh.Mark{
      __meta__: #Ecto.Schema.Metadata<:loaded, "marks">,
      id: "90c6036a-9bd1-4b65-82d5-f121ec4d7867",
      body: nil,
      order: 2,
      state: :draft,
      verse_id: nil,
      sheaf_id: "7f4ab16b-0caf-4009-ba2a-3ddded81d9aa",
      sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>,
      binding_id: "b92f990d-99a2-4f04-a2d4-d1135021ee8c",
      binding: %Vyasa.Adapters.Binding{
        __meta__: #Ecto.Schema.Metadata<:loaded, "bindings">,
        id: "b92f990d-99a2-4f04-a2d4-d1135021ee8c",
        w_type: nil,
        field_key: ["target", "body_translit_meant"],
        node_id: nil,
        verse_id: nil,
        verse: #Ecto.Association.NotLoaded<association :verse is not loaded>,
        chapter_no: nil,
        chapter: #Ecto.Association.NotLoaded<association :chapter is not loaded>,
        source_id: nil,
        source: #Ecto.Association.NotLoaded<association :source is not loaded>,
        translation_id: "97a7a662-a91b-486f-93e8-7ae932d01a1a",
        translation: #Ecto.Association.NotLoaded<association :translation is not loaded>,
        sheaf_id: nil,
        sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>,
        window: nil
      },
      inserted_at: ~U[2024-10-11 09:03:00Z],
      updated_at: ~U[2024-10-11 09:03:00Z]
    }
  ],
  inserted_at: ~N[2024-09-27 00:51:48],
  updated_at: ~N[2024-09-27 00:51:48]
}
[debug] Replied in 81ms
[debug] HANDLE EVENT "verses::focus_toggle_on_quick_mark_drafting" in VyasaWeb.ModeLive.Mediator
  Component: VyasaWeb.Context.Read
  Parameters: %{"is_focusing?" => false, "value" => ""}
[debug] Replied in 129µs
iex([email protected])17>

* marks order force

* old man mark is not feeling so good

* ReWrite how marks get initialised @ :show_verse (#119)

* Minor change in fn signature

* Add init_draft_reflector()

---------

Co-authored-by: ks0m1c_dharma <[email protected]>

* Minor changes

* Add a generic modal wrapper (#120)

* Add generic debug dump component

This makes life easy when wiring things up

* Rename namespace for Context.Read.*

* Groundwork: add discuss component w sheafs

* Init Context.Components mod for common components

* Add skeletons for Sheaf Container

Container managers sheaf state within itself.
Should actually make the verse-matrix use this container, sometime.

* Minor changes, add some TODOs to share

explicit todos

Minor change

* Add live component EditableMarkDisplay

* Add UI improvements to EditableMarkDisplay

The edit button on quick draft should only be seen when the dropdown is
expanded and all the marks can be seen. The general pattern I'm trying
to follow is that buttons should only be shown when an action makes
sense. So here, if the user can't even see the marks currently
accumulating, then the user shouldn't have the chance to edit any marks.

Notice that the EditableMarkDisplay is a live_component that is a child
of a function component (collapsible_marks_display). This is so that it can keep its own state and
do it's own event-handling. I'm not sure if this is pattern-breaking.
A reference to the actual parent live_component that calls collapsible_marks_display
will always be there in case there's a need for the parent to handle
any particular events. So comms b/w live_components is still going to be
via phx-target values.

* Change <input/> -> <textarea/> fr quick_draft_form

* Add tailwind config for custom svg icons

not sure how the scaling for this works, seems like i can't just put in
the class="h-5 w-5" to do the scaling

* Let custom svg be scalable

* Subtly shift the ping indicator to control panel

* Marks ordering in Sheaf and L-Trees  (#114)

* do sheafs grow on trees

* sangh session dealing with lineage

* Solve initial order problem

* fix: ensure non-null id used @ EditableMarkDisplay

---------

Co-authored-by: ks0m1c_dharma <[email protected]>

* Trigger Diff

* TOMBSTONING

* Fix bugs and revert ui for read_mode:delete marks

1.  JIT generate id for marks yet to be inserted to the db: instead of
    using a temp id, I'm actually assigning a JIT-generated id for a
    mark even if that isn't inserted into the db yet. this has two
    benefits: div ids have meaningful static ids (e.g.
    mark-container-\<\> mark.id) regardless of whether that mark has
    been inserted into the db or not. While doing this, the changeset
    for marks has been udpated to add id as well. This fixes a bunch of
    id-based errors as well.

2.  while doing 1, it came to light that the bindHoverune handlers were
    not handling the draft mark update properly (i.e. not using the
    already existing update function in mark) . it's changed now,
    example of the diff:

    ``` diff
      @impl true
      def handle_event(
            "bindHoveRune",
            %{"binding" => bind = %{"verse_id" => verse_id}},
            %{
              assigns: %{
                kv_verses: verses,
                marks: [%Mark{state: :draft, verse_id: curr_verse_id} = d_mark | marks]
              }
            } = socket
          )
          when is_binary(curr_verse_id) and verse_id != curr_verse_id do
        # binding here blocks the stream from appending to quote
        bind = Draft.bind_node(bind)

        bound_verses =
          verses
           |> then(&put_in(&1[verse_id].binding, bind))
           |> then(&put_in(&1[curr_verse_id].binding, nil))

    +    updated_draft_mark = d_mark |> Mark.update_mark(%{binding: bind, verse_id: verse_id})
    +
         {:noreply,
          socket
          |> mutate_verses(curr_verse_id, bound_verses)
          |> mutate_verses(verse_id, bound_verses)
    -     |> assign(:marks, [%{d_mark | binding: bind, verse_id: verse_id} | marks])}
    +     |> assign(:marks, [updated_draft_mark | marks])}
       end
    ```

3.  add ui state structs: all of the relevant ui states have structs
    that are intended to be static interfaces. this felt better than
    directly keeping state within various sockets and is done with a
    view to remove live components and change them to function
    components wherever possible.

4.  bugfix for `order()`:

    - it had an off-by-one-error
    - shifted it to Vyasa.Sangh.Mark
    - also note that the order shall be 1-indexed instead of 0-indexed
      for human-friendliness

5.  minor fixes:

    1.  fix update<sub>mark</sub> default argument

        ``` diff
        -def update_mark(%Mark{} = draft_mark, opts \\ []) do
        +def update_mark(%Mark{} = draft_mark, opts \\ %{}) do
        ```

1.  In this commit, the marks<sub>ui</sub> is NOT kept by the read
    context module, that's why when I update things by create mark or
    delete mark, the ui state is not preserved and initial, default
    state is seen. This was intentionally done in this commit because
    I'm having problems with duplicate ids for verses for some reason,
    I'll show it in the next commit, so that the problem can be clearly
    seen.

* [BUGGY] keep marks_ui within ReadContext

This is buggy, not sure why there's a duplicate yet.  will come back to
it after lunch

Replication Steps:
1. delete all marks and see there's no error
2. create first mark ==> no error
3. create second mark ==> crashes due to duplicate verse id

Crash dump:

[debug] Replied in 13ms
[error] GenServer #PID<0.8416.0> terminating
** (RuntimeError) found duplicate ID "verse-7d9d588a-34fc-4f19-b974-fc32b49b6a61" for component VyasaWeb.Context.Read.VerseMatrix when rendering template
    (phoenix_live_view 1.0.0-rc.6) lib/phoenix_live_view/diff.ex:634: anonymous fn/5 in Phoenix.LiveView.Diff.render_pending_components/6
    (elixir 1.17.2) lib/enum.ex:2531: Enum."-reduce/3-lists^foldl/2-0-"/3
    (phoenix_live_view 1.0.0-rc.6) lib/phoenix_live_view/diff.ex:631: anonymous fn/4 in Phoenix.LiveView.Diff.render_pending_components/6
    (stdlib 5.2.3) maps.erl:416: :maps.fold_1/4
    (phoenix_live_view 1.0.0-rc.6) lib/phoenix_live_view/diff.ex:625: Phoenix.LiveView.Diff.render_pending_components/6
    (phoenix_live_view 1.0.0-rc.6) lib/phoenix_live_view/diff.ex:217: Phoenix.LiveView.Diff.write_component/4
    (phoenix_live_view 1.0.0-rc.6) lib/phoenix_live_view/channel.ex:662: Phoenix.LiveView.Channel.component_handle/4
    (stdlib 5.2.3) gen_server.erl:1095: :gen_server.try_handle_info/3
    (stdlib 5.2.3) gen_server.erl:1183: :gen_server.handle_msg/6
    (stdlib 5.2.3) proc_lib.erl:251: :proc_lib.wake_up/3
Last message: %Phoenix.Socket.Message{topic: "lv:phx-F_1MH_6F0ciqVqwi", event: "event", payload: %{"cid" => 3, "event" => "createMark", "type" => "form", "value" => "body=how+about+now%2C+any+duplicate%3F"}, ref: "23", join_ref: "4"}
State: %{socket: #Phoenix.LiveView.Socket<id: "phx-F_1MH_6F0ciqVqwi", endpoint: VyasaWeb.Endpoint, view: VyasaWeb.ModeLive.Mediator, parent_pid: nil, root_pid: #PID<0.8416.0>, router: VyasaWeb.Router, assigns: %{mode: %VyasaWeb.ModeLive.UserMode{mode: "read", default_ui_state: %VyasaWeb.ModeLive.UiState{show_media_bridge?: true, show_action_bar?: true}, mode_icon_name: "hero-book-open", quick_actions: [:mark_quote, :bookmark], control_panel_modes: ["discuss"], mode_actions: [:mark_quote, :bookmark], action_bar_actions: [:nav_back, :nav_fwd], action_bar_info_types: nil, action_bar_component: VyasaWeb.MediaLive.MediaBridge, action_bar_component_selector: "media-bridge", control_panel_component: VyasaWeb.ControlPanel, control_panel_component_selector: "control-panel", mode_context_component: VyasaWeb.Context.Read, mode_context_component_selector: "read"}, session: %VyasaWeb.Session{name: "ritesh kumar", id: "IhrQV0ypqg8bHakbvb2bymNF", active: true, sangh: %Vyasa.Sangh.Session{__meta__: #Ecto.Schema.Metadata<:loaded, "sessions">, id: "164eb05d-221a-4939-b180-8394e1a5515f", sheafs: #Ecto.Association.NotLoaded<association :sheafs is not loaded>, inserted_at: ~U[2024-09-27 00:51:48Z], updated_at: ~U[2024-09-27 00:51:48Z]}, last_opened: "2024-09-23T11:03:32.022987Z"}, __changed__: %{}, flash: %{}, locale: "en-GB", url_params: %{"chap_no" => "1", "source_title" => "hanuman_chalisa"}, live_action: :show_verses, ui_state: %VyasaWeb.ModeLive.UiState{show_media_bridge?: true, show_action_bar?: true}, device_type: :desktop, tz: %{timezone: "Asia/Singapore", timezone_offset: 480}}, transport_pid: #PID<0.8403.0>, ...>, components: {%{15 => {VyasaWeb.Context.Read.VerseMatrix, "verse-aa3ad88b-0de1-443e-b471-c08a44e67c61", %{id: "verse-aa3ad88b-0de1-443e-b471-c08a44e67c61", edge: [%{title: "1.10", field: [:body], verseup: {:big, "dn"}}, %{node: %Vyasa.Written.Translation{__meta__: #Ecto.Schema.Metadata<:loaded, "translations">, id: "651676b6-ffc3-41c1-b525-f376989f639e", lang: "en", type: "verses", target: %Vyasa.Written.Translation.Target{id: "dd20a94f-8f34-49f8-8da8-4321cfecf172", title: nil, title_translit: nil, body: "प्रभु चरित्र सुनिबे को रसिया ।\n\nराम लखन सीता मन बसिया ॥८॥", body_meant: nil, body_translit: "prabhu caritra sunibe ko rasiyā .\n\nrāma lakhana sītā mana basiyā ..8..", body_translit_meant: "You feel extremely delighted in listening to Lord Rama’s doings and conduct. Lord Rama, Mother Sita, and Lord Laxmana dwell forever in your heart."}, verse_id: "aa3ad88b-0de1-443e-b471-c08a44e67c61", verse: #Ecto.Association.NotLoaded<association :verse is not loaded>, chapter_no: nil, chapter: #Ecto.Association.NotLoaded<association :chapter is not loaded>, source_id: "63918acd-77a9-451a-b8d1-8d5b73208eae", source: #Ecto.Association.NotLoaded<association :source is not loaded>}, field: [:target, :body_translit], verseup: :mid}, %{node: %Vyasa.Written.Translation{__meta__: #Ecto.Schema.Metadata<:loaded, "translations">, id: "651676b6-ffc3-41c1-b525-f376989f639e", lang: "en", type: "verses", target: %Vyasa.Written.Translation.Target{id: "dd20a94f-8f34-49f8-8da8-4321cfecf172", title: nil, title_translit: nil, body: "प्रभु चरित्र सुनिबे को रसिया ।\n\nराम लखन सीता मन बसिया ॥८॥", body_meant: nil, body_translit: "prabhu caritra sunibe ko rasiyā .\n\nrāma lakhana sītā mana basiyā ..8..", body_translit_meant: "You feel extremely delighted in listening to Lord Rama’s doings and conduct. Lord Rama, Mother Sita, and Lord Laxmana dwell forever in your heart."}, verse_id: "aa3ad88b-0de1-443e-b471-c08a44e67c61", verse: #Ecto.Association.NotLoaded<association :verse is not loaded>, chapter_no: nil, chapter: #Ecto.Association.NotLoaded<association :chapter is not loaded>, source_id: "63918acd-77a9-451a-b8d1-8d5b73208eae", source: #Ecto.Association.NotLoaded<association :source is not loaded>}, field: [:target, :body_translit_meant], verseup: :mid}, %{node: %Vyasa.Written.Translation{__meta__: #Ecto.Schema.Metadata<:loaded, "translations">, id: "651676b6-ffc3-41c1-b525-f376989f639e", lang: "en", type: "verses", target: %Vyasa.Written.Translation.Target{id: "dd20a94f-8f34-49f8-8da8-4321cfecf172", title: nil, title_translit: nil, body: "प्रभु चरित्र सुनिबे को रसिया ।\n\nराम लखन सीता मन बसिया ॥८॥", body_meant: nil, body_translit: "prabhu caritra sunibe ko rasiyā .\n\nrāma lakhana sītā mana basiyā ..8..", body_translit_meant: "You feel extremely delighted in listening to Lord Rama’s doings and conduct. Lord Rama, Mother Sita, and Lord Laxmana dwell forever in your heart."}, verse_id: "aa3ad88b-0de1-443e-b471-c08a44e67c61", verse: #Ecto.Association.NotLoaded<association :verse is not loaded>, chapter_no: nil, chapter: #Ecto.Association.NotLoaded<association :chapter is not loaded>, source_id: "63918acd-77a9-451a-b8d1-8d5b73208eae", source: #Ecto.Association.NotLoaded<association :source is not loaded>}, field: [:target, :body], verseup: :mid}], __changed__: %{}, flash: %{}, marks: [%Vyasa.Sangh.Mark{__meta__: #Ecto.Schema.Metadata<:loaded, "marks">, id: "5dfdb167-6c57-46dd-a0c4-10b52cb03a85", body: "wonderful", order: 2, state: :live, verse_id: nil, sheaf_id: "7f4ab16b-0caf-4009-ba2a-3ddded81d9aa", sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>, binding_id: "001da594-3808-46cf-9b9c-5dfb3559780e", binding: %Vyasa.Adapters.Binding{__meta__: #Ecto.Schema.Metadata<:loaded, "bindings">, id: "001da594-3808-46cf-9b9c-5dfb3559780e", w_type: nil, field_key: ["target", "body_translit_meant"], node_id: nil, verse_id: nil, verse: #Ecto.Association.NotLoaded<association :verse is not loaded>, chapter_no: nil, chapter: #Ecto.Association.NotLoaded<association :chapter is not loaded>, source_id: nil, source: #Ecto.Association.NotLoaded<association :source is not loaded>, translation_id: "97a7a662-a91b-486f-93e8-7ae932d01a1a", translation: #Ecto.Association.NotLoaded<association :translation is not loaded>, sheaf_id: nil, sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>, window: nil}, inserted_at: ~U[2024-10-11 04:31:50Z], updated_at: ~U[2024-10-11 04:31:50Z]}, %Vyasa.Sangh.Mark{__meta__: #Ecto.Schema.Metadata<:loaded, "marks">, id: "273a093d-4f90-40a4-b19a-2f8f7825d201", body: "truncated utc datetime", order: 1, state: :live, verse_id: nil, sheaf_id: "7f4ab16b-0caf-4009-ba2a-3ddded81d9aa", sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>, binding_id: "ef39315b-530c-4841-ba32-86773f451727", binding: %Vyasa.Adapt (truncated)
[debug] MOUNT VyasaWeb.ModeLive.Mediator
  Parameters: %{"chap_no" => "1", "source_title" => "hanuman_chalisa"}
  Session: %{"_csrf_token" => "DJ-RIoXwEzHW82rbb21le_8k"}
[debug] QUERY OK source="sessions" db=3.5ms idle=1690.4ms
SELECT s0."id", s0."inserted_at", s0."updated_at" FROM "sessions" AS s0 WHERE (s0."id" = $1) ["164eb05d-221a-4939-b180-8394e1a5515f"]
↳

* Fix duplicate id issue on verse matrix

* Standardise use of @event_target, cleanups

When using @event_target, the intent is that phx-target values
will be passed around. This must be agnostic to the 2 main ways of
supplying that argument, as a HTML selector, or as a module name (or @myself).
Therefore, we should discourage ourselves from doing format-strings at
the point of the @event_target being supplied as an argument, meaning:

good, because agnostic:
phx-target={@event_target}

bad, because hardcoded:
phx-target={"#" <> @event_target}
* in this case, the event trigger will t…
* Add generic debug dump component

This makes life easy when wiring things up

* Rename namespace for Context.Read.*

* Groundwork: add discuss component w sheafs

* Init Context.Components mod for common components

* Add skeletons for Sheaf Container

Container managers sheaf state within itself.
Should actually make the verse-matrix use this container, sometime.

* Minor changes, add some TODOs to share

explicit todos

Minor change

* Add live component EditableMarkDisplay

* Add UI improvements to EditableMarkDisplay

The edit button on quick draft should only be seen when the dropdown is
expanded and all the marks can be seen. The general pattern I'm trying
to follow is that buttons should only be shown when an action makes
sense. So here, if the user can't even see the marks currently
accumulating, then the user shouldn't have the chance to edit any marks.

Notice that the EditableMarkDisplay is a live_component that is a child
of a function component (collapsible_marks_display). This is so that it can keep its own state and
do it's own event-handling. I'm not sure if this is pattern-breaking.
A reference to the actual parent live_component that calls collapsible_marks_display
will always be there in case there's a need for the parent to handle
any particular events. So comms b/w live_components is still going to be
via phx-target values.

* Change <input/> -> <textarea/> fr quick_draft_form

* Add tailwind config for custom svg icons

not sure how the scaling for this works, seems like i can't just put in
the class="h-5 w-5" to do the scaling

* Let custom svg be scalable

* Subtly shift the ping indicator to control panel

* Marks ordering in Sheaf and L-Trees  (#114)

* do sheafs grow on trees

* sangh session dealing with lineage

* Solve initial order problem

* fix: ensure non-null id used @ EditableMarkDisplay

---------

Co-authored-by: ks0m1c_dharma <[email protected]>

* Trigger Diff

* TOMBSTONING

* Fix bugs and revert ui for read_mode:delete marks

1.  JIT generate id for marks yet to be inserted to the db: instead of
    using a temp id, I'm actually assigning a JIT-generated id for a
    mark even if that isn't inserted into the db yet. this has two
    benefits: div ids have meaningful static ids (e.g.
    mark-container-\<\> mark.id) regardless of whether that mark has
    been inserted into the db or not. While doing this, the changeset
    for marks has been udpated to add id as well. This fixes a bunch of
    id-based errors as well.

2.  while doing 1, it came to light that the bindHoverune handlers were
    not handling the draft mark update properly (i.e. not using the
    already existing update function in mark) . it's changed now,
    example of the diff:

    ``` diff
      @impl true
      def handle_event(
            "bindHoveRune",
            %{"binding" => bind = %{"verse_id" => verse_id}},
            %{
              assigns: %{
                kv_verses: verses,
                marks: [%Mark{state: :draft, verse_id: curr_verse_id} = d_mark | marks]
              }
            } = socket
          )
          when is_binary(curr_verse_id) and verse_id != curr_verse_id do
        # binding here blocks the stream from appending to quote
        bind = Draft.bind_node(bind)

        bound_verses =
          verses
           |> then(&put_in(&1[verse_id].binding, bind))
           |> then(&put_in(&1[curr_verse_id].binding, nil))

    +    updated_draft_mark = d_mark |> Mark.update_mark(%{binding: bind, verse_id: verse_id})
    +
         {:noreply,
          socket
          |> mutate_verses(curr_verse_id, bound_verses)
          |> mutate_verses(verse_id, bound_verses)
    -     |> assign(:marks, [%{d_mark | binding: bind, verse_id: verse_id} | marks])}
    +     |> assign(:marks, [updated_draft_mark | marks])}
       end
    ```

3.  add ui state structs: all of the relevant ui states have structs
    that are intended to be static interfaces. this felt better than
    directly keeping state within various sockets and is done with a
    view to remove live components and change them to function
    components wherever possible.

4.  bugfix for `order()`:

    - it had an off-by-one-error
    - shifted it to Vyasa.Sangh.Mark
    - also note that the order shall be 1-indexed instead of 0-indexed
      for human-friendliness

5.  minor fixes:

    1.  fix update<sub>mark</sub> default argument

        ``` diff
        -def update_mark(%Mark{} = draft_mark, opts \\ []) do
        +def update_mark(%Mark{} = draft_mark, opts \\ %{}) do
        ```

1.  In this commit, the marks<sub>ui</sub> is NOT kept by the read
    context module, that's why when I update things by create mark or
    delete mark, the ui state is not preserved and initial, default
    state is seen. This was intentionally done in this commit because
    I'm having problems with duplicate ids for verses for some reason,
    I'll show it in the next commit, so that the problem can be clearly
    seen.

* [BUGGY] keep marks_ui within ReadContext

This is buggy, not sure why there's a duplicate yet.  will come back to
it after lunch

Replication Steps:
1. delete all marks and see there's no error
2. create first mark ==> no error
3. create second mark ==> crashes due to duplicate verse id

Crash dump:

[debug] Replied in 13ms
[error] GenServer #PID<0.8416.0> terminating
** (RuntimeError) found duplicate ID "verse-7d9d588a-34fc-4f19-b974-fc32b49b6a61" for component VyasaWeb.Context.Read.VerseMatrix when rendering template
    (phoenix_live_view 1.0.0-rc.6) lib/phoenix_live_view/diff.ex:634: anonymous fn/5 in Phoenix.LiveView.Diff.render_pending_components/6
    (elixir 1.17.2) lib/enum.ex:2531: Enum."-reduce/3-lists^foldl/2-0-"/3
    (phoenix_live_view 1.0.0-rc.6) lib/phoenix_live_view/diff.ex:631: anonymous fn/4 in Phoenix.LiveView.Diff.render_pending_components/6
    (stdlib 5.2.3) maps.erl:416: :maps.fold_1/4
    (phoenix_live_view 1.0.0-rc.6) lib/phoenix_live_view/diff.ex:625: Phoenix.LiveView.Diff.render_pending_components/6
    (phoenix_live_view 1.0.0-rc.6) lib/phoenix_live_view/diff.ex:217: Phoenix.LiveView.Diff.write_component/4
    (phoenix_live_view 1.0.0-rc.6) lib/phoenix_live_view/channel.ex:662: Phoenix.LiveView.Channel.component_handle/4
    (stdlib 5.2.3) gen_server.erl:1095: :gen_server.try_handle_info/3
    (stdlib 5.2.3) gen_server.erl:1183: :gen_server.handle_msg/6
    (stdlib 5.2.3) proc_lib.erl:251: :proc_lib.wake_up/3
Last message: %Phoenix.Socket.Message{topic: "lv:phx-F_1MH_6F0ciqVqwi", event: "event", payload: %{"cid" => 3, "event" => "createMark", "type" => "form", "value" => "body=how+about+now%2C+any+duplicate%3F"}, ref: "23", join_ref: "4"}
State: %{socket: #Phoenix.LiveView.Socket<id: "phx-F_1MH_6F0ciqVqwi", endpoint: VyasaWeb.Endpoint, view: VyasaWeb.ModeLive.Mediator, parent_pid: nil, root_pid: #PID<0.8416.0>, router: VyasaWeb.Router, assigns: %{mode: %VyasaWeb.ModeLive.UserMode{mode: "read", default_ui_state: %VyasaWeb.ModeLive.UiState{show_media_bridge?: true, show_action_bar?: true}, mode_icon_name: "hero-book-open", quick_actions: [:mark_quote, :bookmark], control_panel_modes: ["discuss"], mode_actions: [:mark_quote, :bookmark], action_bar_actions: [:nav_back, :nav_fwd], action_bar_info_types: nil, action_bar_component: VyasaWeb.MediaLive.MediaBridge, action_bar_component_selector: "media-bridge", control_panel_component: VyasaWeb.ControlPanel, control_panel_component_selector: "control-panel", mode_context_component: VyasaWeb.Context.Read, mode_context_component_selector: "read"}, session: %VyasaWeb.Session{name: "ritesh kumar", id: "IhrQV0ypqg8bHakbvb2bymNF", active: true, sangh: %Vyasa.Sangh.Session{__meta__: #Ecto.Schema.Metadata<:loaded, "sessions">, id: "164eb05d-221a-4939-b180-8394e1a5515f", sheafs: #Ecto.Association.NotLoaded<association :sheafs is not loaded>, inserted_at: ~U[2024-09-27 00:51:48Z], updated_at: ~U[2024-09-27 00:51:48Z]}, last_opened: "2024-09-23T11:03:32.022987Z"}, __changed__: %{}, flash: %{}, locale: "en-GB", url_params: %{"chap_no" => "1", "source_title" => "hanuman_chalisa"}, live_action: :show_verses, ui_state: %VyasaWeb.ModeLive.UiState{show_media_bridge?: true, show_action_bar?: true}, device_type: :desktop, tz: %{timezone: "Asia/Singapore", timezone_offset: 480}}, transport_pid: #PID<0.8403.0>, ...>, components: {%{15 => {VyasaWeb.Context.Read.VerseMatrix, "verse-aa3ad88b-0de1-443e-b471-c08a44e67c61", %{id: "verse-aa3ad88b-0de1-443e-b471-c08a44e67c61", edge: [%{title: "1.10", field: [:body], verseup: {:big, "dn"}}, %{node: %Vyasa.Written.Translation{__meta__: #Ecto.Schema.Metadata<:loaded, "translations">, id: "651676b6-ffc3-41c1-b525-f376989f639e", lang: "en", type: "verses", target: %Vyasa.Written.Translation.Target{id: "dd20a94f-8f34-49f8-8da8-4321cfecf172", title: nil, title_translit: nil, body: "प्रभु चरित्र सुनिबे को रसिया ।\n\nराम लखन सीता मन बसिया ॥८॥", body_meant: nil, body_translit: "prabhu caritra sunibe ko rasiyā .\n\nrāma lakhana sītā mana basiyā ..8..", body_translit_meant: "You feel extremely delighted in listening to Lord Rama’s doings and conduct. Lord Rama, Mother Sita, and Lord Laxmana dwell forever in your heart."}, verse_id: "aa3ad88b-0de1-443e-b471-c08a44e67c61", verse: #Ecto.Association.NotLoaded<association :verse is not loaded>, chapter_no: nil, chapter: #Ecto.Association.NotLoaded<association :chapter is not loaded>, source_id: "63918acd-77a9-451a-b8d1-8d5b73208eae", source: #Ecto.Association.NotLoaded<association :source is not loaded>}, field: [:target, :body_translit], verseup: :mid}, %{node: %Vyasa.Written.Translation{__meta__: #Ecto.Schema.Metadata<:loaded, "translations">, id: "651676b6-ffc3-41c1-b525-f376989f639e", lang: "en", type: "verses", target: %Vyasa.Written.Translation.Target{id: "dd20a94f-8f34-49f8-8da8-4321cfecf172", title: nil, title_translit: nil, body: "प्रभु चरित्र सुनिबे को रसिया ।\n\nराम लखन सीता मन बसिया ॥८॥", body_meant: nil, body_translit: "prabhu caritra sunibe ko rasiyā .\n\nrāma lakhana sītā mana basiyā ..8..", body_translit_meant: "You feel extremely delighted in listening to Lord Rama’s doings and conduct. Lord Rama, Mother Sita, and Lord Laxmana dwell forever in your heart."}, verse_id: "aa3ad88b-0de1-443e-b471-c08a44e67c61", verse: #Ecto.Association.NotLoaded<association :verse is not loaded>, chapter_no: nil, chapter: #Ecto.Association.NotLoaded<association :chapter is not loaded>, source_id: "63918acd-77a9-451a-b8d1-8d5b73208eae", source: #Ecto.Association.NotLoaded<association :source is not loaded>}, field: [:target, :body_translit_meant], verseup: :mid}, %{node: %Vyasa.Written.Translation{__meta__: #Ecto.Schema.Metadata<:loaded, "translations">, id: "651676b6-ffc3-41c1-b525-f376989f639e", lang: "en", type: "verses", target: %Vyasa.Written.Translation.Target{id: "dd20a94f-8f34-49f8-8da8-4321cfecf172", title: nil, title_translit: nil, body: "प्रभु चरित्र सुनिबे को रसिया ।\n\nराम लखन सीता मन बसिया ॥८॥", body_meant: nil, body_translit: "prabhu caritra sunibe ko rasiyā .\n\nrāma lakhana sītā mana basiyā ..8..", body_translit_meant: "You feel extremely delighted in listening to Lord Rama’s doings and conduct. Lord Rama, Mother Sita, and Lord Laxmana dwell forever in your heart."}, verse_id: "aa3ad88b-0de1-443e-b471-c08a44e67c61", verse: #Ecto.Association.NotLoaded<association :verse is not loaded>, chapter_no: nil, chapter: #Ecto.Association.NotLoaded<association :chapter is not loaded>, source_id: "63918acd-77a9-451a-b8d1-8d5b73208eae", source: #Ecto.Association.NotLoaded<association :source is not loaded>}, field: [:target, :body], verseup: :mid}], __changed__: %{}, flash: %{}, marks: [%Vyasa.Sangh.Mark{__meta__: #Ecto.Schema.Metadata<:loaded, "marks">, id: "5dfdb167-6c57-46dd-a0c4-10b52cb03a85", body: "wonderful", order: 2, state: :live, verse_id: nil, sheaf_id: "7f4ab16b-0caf-4009-ba2a-3ddded81d9aa", sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>, binding_id: "001da594-3808-46cf-9b9c-5dfb3559780e", binding: %Vyasa.Adapters.Binding{__meta__: #Ecto.Schema.Metadata<:loaded, "bindings">, id: "001da594-3808-46cf-9b9c-5dfb3559780e", w_type: nil, field_key: ["target", "body_translit_meant"], node_id: nil, verse_id: nil, verse: #Ecto.Association.NotLoaded<association :verse is not loaded>, chapter_no: nil, chapter: #Ecto.Association.NotLoaded<association :chapter is not loaded>, source_id: nil, source: #Ecto.Association.NotLoaded<association :source is not loaded>, translation_id: "97a7a662-a91b-486f-93e8-7ae932d01a1a", translation: #Ecto.Association.NotLoaded<association :translation is not loaded>, sheaf_id: nil, sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>, window: nil}, inserted_at: ~U[2024-10-11 04:31:50Z], updated_at: ~U[2024-10-11 04:31:50Z]}, %Vyasa.Sangh.Mark{__meta__: #Ecto.Schema.Metadata<:loaded, "marks">, id: "273a093d-4f90-40a4-b19a-2f8f7825d201", body: "truncated utc datetime", order: 1, state: :live, verse_id: nil, sheaf_id: "7f4ab16b-0caf-4009-ba2a-3ddded81d9aa", sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>, binding_id: "ef39315b-530c-4841-ba32-86773f451727", binding: %Vyasa.Adapt (truncated)
[debug] MOUNT VyasaWeb.ModeLive.Mediator
  Parameters: %{"chap_no" => "1", "source_title" => "hanuman_chalisa"}
  Session: %{"_csrf_token" => "DJ-RIoXwEzHW82rbb21le_8k"}
[debug] QUERY OK source="sessions" db=3.5ms idle=1690.4ms
SELECT s0."id", s0."inserted_at", s0."updated_at" FROM "sessions" AS s0 WHERE (s0."id" = $1) ["164eb05d-221a-4939-b180-8394e1a5515f"]
↳

* Fix duplicate id issue on verse matrix

* Standardise use of @event_target, cleanups

When using @event_target, the intent is that phx-target values
will be passed around. This must be agnostic to the 2 main ways of
supplying that argument, as a HTML selector, or as a module name (or @myself).
Therefore, we should discourage ourselves from doing format-strings at
the point of the @event_target being supplied as an argument, meaning:

good, because agnostic:
phx-target={@event_target}

bad, because hardcoded:
phx-target={"#" <> @event_target}
* in this case, the event trigger will throw a dom error.

* [Attempt]: Sanitise, defrag orders in marks-list

If this is an anti-pattern, then this commit should be reverted.

* UI fixes: hide buttons on marks when !is_editable?

* Add in stub event handlers to prevent crashes

Temporary stuff, will be addressed in immediate-next PR

* Minor changes

* Toggle edit state for marks content

* Partial implementation of edit marks

the form stuff doesn't exist so it's not wired up yet. To be frank,
im' not sure how to set up a form without it needing to hold state.

* [BUGGY] Wire up form update for edit

this does the following:
1. wires up the form like how we usedd it in createMark
2. actually captures the event properly within the event handler,
everything looks good at that point, even the edit_mark_in_marks
function on inspection looks good
3. the marks is getting assigned to properly because the newly edited
mark content is seen after doing a dom refresh
4. HOWEVER, the print statement at the sheaf_update function DOES NOT
show the correct, updated marks in the sheaf

here's a dump for it for reference

[debug] HANDLE EVENT "editMarkContent" in VyasaWeb.ModeLive.Mediator
  Component: VyasaWeb.Context.Read
  Parameters: %{"mark_id" => "02218551-591f-4450-abbd-a7b7d76fd48e"}
[debug] Replied in 2ms
[debug] HANDLE EVENT "editMarkContent" in VyasaWeb.ModeLive.Mediator
  Component: VyasaWeb.Context.Read
  Parameters: %{"mark_body" => "  testing\n\n\nwhat hte heck", "mark_id" => "02218551-591f-4450-abbd-a7b7d76fd48e"}
>>> UPDATE SHEAF -- SHOULD BE WRITING TO DB NOW: %Vyasa.Sangh.Sheaf{
  __meta__: #Ecto.Schema.Metadata<:loaded, "sheafs">,
  id: "7f4ab16b-0caf-4009-ba2a-3ddded81d9aa",
  body: nil,
  active: true,
  path: %EctoLtree.LabelTree{labels: ["7f4ab16b"]},
  signature: nil,
  traits: ["draft"],
  child_count: 0,
  session_id: "164eb05d-221a-4939-b180-8394e1a5515f",
  session: #Ecto.Association.NotLoaded<association :session is not loaded>,
  parent_id: nil,
  parent: #Ecto.Association.NotLoaded<association :parent is not loaded>,
  marks: [
    %Vyasa.Sangh.Mark{
      __meta__: #Ecto.Schema.Metadata<:loaded, "marks">,
      id: "555eb625-e392-496e-9831-4f4c130be6fd",
      body: "wonderful stuff",
      order: 5,
      state: :live,
      verse_id: nil,
      sheaf_id: "7f4ab16b-0caf-4009-ba2a-3ddded81d9aa",
      sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>,
      binding_id: "072124d0-5e27-4601-832f-35eaa6426879",
      binding: %Vyasa.Adapters.Binding{
        __meta__: #Ecto.Schema.Metadata<:loaded, "bindings">,
        id: "072124d0-5e27-4601-832f-35eaa6426879",
        w_type: nil,
        field_key: ["target", "body_translit_meant"],
        node_id: nil,
        verse_id: nil,
        verse: #Ecto.Association.NotLoaded<association :verse is not loaded>,
        chapter_no: nil,
        chapter: #Ecto.Association.NotLoaded<association :chapter is not loaded>,
        source_id: nil,
        source: #Ecto.Association.NotLoaded<association :source is not loaded>,
        translation_id: "97a7a662-a91b-486f-93e8-7ae932d01a1a",
        translation: #Ecto.Association.NotLoaded<association :translation is not loaded>,
        sheaf_id: nil,
        sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>,
        window: nil
      },
      inserted_at: ~U[2024-10-12 08:46:54Z],
      updated_at: ~U[2024-10-12 08:46:54Z]
    },
    %Vyasa.Sangh.Mark{
      __meta__: #Ecto.Schema.Metadata<:loaded, "marks">,
      id: "b22a5661-8268-4875-be26-a12256414136",
      body: nil,
      order: 5,
      state: :draft,
      verse_id: nil,
      sheaf_id: "7f4ab16b-0caf-4009-ba2a-3ddded81d9aa",
      sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>,
      binding_id: "90e18044-73b2-4ede-a149-a381de893b9f",
      binding: %Vyasa.Adapters.Binding{
        __meta__: #Ecto.Schema.Metadata<:loaded, "bindings">,
        id: "90e18044-73b2-4ede-a149-a381de893b9f",
        w_type: nil,
        field_key: ["target", "body_translit_meant"],
        node_id: nil,
        verse_id: nil,
        verse: #Ecto.Association.NotLoaded<association :verse is not loaded>,
        chapter_no: nil,
        chapter: #Ecto.Association.NotLoaded<association :chapter is not loaded>,
        source_id: nil,
        source: #Ecto.Association.NotLoaded<association :source is not loaded>,
        translation_id: "fc80709a-39dc-4b9c-95c3-1d64ce818302",
        translation: #Ecto.Association.NotLoaded<association :translation is not loaded>,
        sheaf_id: nil,
        sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>,
        window: nil
      },
      inserted_at: ~U[2024-10-12 09:52:40Z],
      updated_at: ~U[2024-10-12 09:52:40Z]
    },
    %Vyasa.Sangh.Mark{
      __meta__: #Ecto.Schema.Metadata<:loaded, "marks">,
      id: "8af43833-575c-4eb8-83b1-eb4e58509e4c",
      body: nil,
      order: 4,
      state: :draft,
      verse_id: nil,
      sheaf_id: "7f4ab16b-0caf-4009-ba2a-3ddded81d9aa",
      sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>,
      binding_id: "23b70937-ed81-47fe-a560-ee14287bff7d",
      binding: %Vyasa.Adapters.Binding{
        __meta__: #Ecto.Schema.Metadata<:loaded, "bindings">,
        id: "23b70937-ed81-47fe-a560-ee14287bff7d",
        w_type: nil,
        field_key: ["target", "body_translit_meant"],
        node_id: nil,
        verse_id: nil,
        verse: #Ecto.Association.NotLoaded<association :verse is not loaded>,
        chapter_no: nil,
        chapter: #Ecto.Association.NotLoaded<association :chapter is not loaded>,
        source_id: nil,
        source: #Ecto.Association.NotLoaded<association :source is not loaded>,
        translation_id: "97a7a662-a91b-486f-93e8-7ae932d01a1a",
        translation: #Ecto.Association.NotLoaded<association :translation is not loaded>,
        sheaf_id: nil,
        sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>,
        window: nil
      },
      inserted_at: ~U[2024-10-12 09:46:13Z],
      updated_at: ~U[2024-10-12 09:46:13Z]
    },
    %Vyasa.Sangh.Mark{
      __meta__: #Ecto.Schema.Metadata<:loaded, "marks">,
      id: "c7ad47e6-629d-4382-936d-64d757772c4e",
      body: nil,
      order: 3,
      state: :draft,
      verse_id: nil,
      sheaf_id: "7f4ab16b-0caf-4009-ba2a-3ddded81d9aa",
      sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>,
      binding_id: "d5758230-7966-4f9b-8c16-ae13998cd71b",
      binding: %Vyasa.Adapters.Binding{
        __meta__: #Ecto.Schema.Metadata<:loaded, "bindings">,
        id: "d5758230-7966-4f9b-8c16-ae13998cd71b",
        w_type: nil,
        field_key: ["target", "body_translit_meant"],
        node_id: nil,
        verse_id: nil,
        verse: #Ecto.Association.NotLoaded<association :verse is not loaded>,
        chapter_no: nil,
        chapter: #Ecto.Association.NotLoaded<association :chapter is not loaded>,
        source_id: nil,
        source: #Ecto.Association.NotLoaded<association :source is not loaded>,
        translation_id: "fc80709a-39dc-4b9c-95c3-1d64ce818302",
        translation: #Ecto.Association.NotLoaded<association :translation is not loaded>,
        sheaf_id: nil,
        sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>,
        window: nil
      },
      inserted_at: ~U[2024-10-12 09:44:09Z],
      updated_at: ~U[2024-10-12 09:44:09Z]
    },
    %Vyasa.Sangh.Mark{
      __meta__: #Ecto.Schema.Metadata<:loaded, "marks">,
      id: "02218551-591f-4450-abbd-a7b7d76fd48e",
      body: "testing",
      order: 2,
      state: :live,
      verse_id: nil,
      sheaf_id: "7f4ab16b-0caf-4009-ba2a-3ddded81d9aa",
      sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>,
      binding_id: "19ffdc82-a5d8-49c3-8b01-1559736dad80",
      binding: %Vyasa.Adapters.Binding{
        __meta__: #Ecto.Schema.Metadata<:loaded, "bindings">,
        id: "19ffdc82-a5d8-49c3-8b01-1559736dad80",
        w_type: nil,
        field_key: ["target", "body_translit_meant"],
        node_id: nil,
        verse_id: nil,
        verse: #Ecto.Association.NotLoaded<association :verse is not loaded>,
        chapter_no: nil,
        chapter: #Ecto.Association.NotLoaded<association :chapter is not loaded>,
        source_id: nil,
        source: #Ecto.Association.NotLoaded<association :source is not loaded>,
        translation_id: "fc80709a-39dc-4b9c-95c3-1d64ce818302",
        translation: #Ecto.Association.NotLoaded<association :translation is not loaded>,
        sheaf_id: nil,
        sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>,
        window: nil
      },
      inserted_at: ~U[2024-10-12 09:43:19Z],
      updated_at: ~U[2024-10-12 09:43:19Z]
    },
    %Vyasa.Sangh.Mark{
      __meta__: #Ecto.Schema.Metadata<:loaded, "marks">,
      id: "90c6036a-9bd1-4b65-82d5-f121ec4d7867",
      body: nil,
      order: 2,
      state: :draft,
      verse_id: nil,
      sheaf_id: "7f4ab16b-0caf-4009-ba2a-3ddded81d9aa",
      sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>,
      binding_id: "b92f990d-99a2-4f04-a2d4-d1135021ee8c",
      binding: %Vyasa.Adapters.Binding{
        __meta__: #Ecto.Schema.Metadata<:loaded, "bindings">,
        id: "b92f990d-99a2-4f04-a2d4-d1135021ee8c",
        w_type: nil,
        field_key: ["target", "body_translit_meant"],
        node_id: nil,
        verse_id: nil,
        verse: #Ecto.Association.NotLoaded<association :verse is not loaded>,
        chapter_no: nil,
        chapter: #Ecto.Association.NotLoaded<association :chapter is not loaded>,
        source_id: nil,
        source: #Ecto.Association.NotLoaded<association :source is not loaded>,
        translation_id: "97a7a662-a91b-486f-93e8-7ae932d01a1a",
        translation: #Ecto.Association.NotLoaded<association :translation is not loaded>,
        sheaf_id: nil,
        sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>,
        window: nil
      },
      inserted_at: ~U[2024-10-11 09:03:00Z],
      updated_at: ~U[2024-10-11 09:03:00Z]
    }
  ],
  inserted_at: ~N[2024-09-27 00:51:48],
  updated_at: ~N[2024-09-27 00:51:48]
}
[debug] Replied in 81ms
[debug] HANDLE EVENT "verses::focus_toggle_on_quick_mark_drafting" in VyasaWeb.ModeLive.Mediator
  Component: VyasaWeb.Context.Read
  Parameters: %{"is_focusing?" => false, "value" => ""}
[debug] Replied in 129µs
iex([email protected])17>

* marks order force

* old man mark is not feeling so good

* ReWrite how marks get initialised @ :show_verse (#119)

* Minor change in fn signature

* Add init_draft_reflector()

* Don't rely on the time async message passing

* Use custom generic_modal_wrapper

This one has more specific callback attributes and tailwind classes can
be injected to it.

* Create data and ui skeletons for sheaf_creator

* Add support for human friendly time formatting

* Setup skeleton for replyto context

Some pending todo functions for how the reply to context shall be determined

* Standardise UI, improve wrapper's default UI

* Improve generic_modal_wrapper styling slots

* Wire sheaf creation form to stubbed event handler

Relevant TODOs have been added

* Use session.name for signature, add handler stubs

* Edit marks in read mode (#118)

* Add generic debug dump component

This makes life easy when wiring things up

* Rename namespace for Context.Read.*

* Groundwork: add discuss component w sheafs

* Init Context.Components mod for common components

* Add skeletons for Sheaf Container

Container managers sheaf state within itself.
Should actually make the verse-matrix use this container, sometime.

* Minor changes, add some TODOs to share

explicit todos

Minor change

* Add live component EditableMarkDisplay

* Add UI improvements to EditableMarkDisplay

The edit button on quick draft should only be seen when the dropdown is
expanded and all the marks can be seen. The general pattern I'm trying
to follow is that buttons should only be shown when an action makes
sense. So here, if the user can't even see the marks currently
accumulating, then the user shouldn't have the chance to edit any marks.

Notice that the EditableMarkDisplay is a live_component that is a child
of a function component (collapsible_marks_display). This is so that it can keep its own state and
do it's own event-handling. I'm not sure if this is pattern-breaking.
A reference to the actual parent live_component that calls collapsible_marks_display
will always be there in case there's a need for the parent to handle
any particular events. So comms b/w live_components is still going to be
via phx-target values.

* Change <input/> -> <textarea/> fr quick_draft_form

* Add tailwind config for custom svg icons

not sure how the scaling for this works, seems like i can't just put in
the class="h-5 w-5" to do the scaling

* Let custom svg be scalable

* Subtly shift the ping indicator to control panel

* Marks ordering in Sheaf and L-Trees  (#114)

* do sheafs grow on trees

* sangh session dealing with lineage

* Solve initial order problem

* fix: ensure non-null id used @ EditableMarkDisplay

---------

Co-authored-by: ks0m1c_dharma <[email protected]>

* Trigger Diff

* TOMBSTONING

* Fix bugs and revert ui for read_mode:delete marks

1.  JIT generate id for marks yet to be inserted to the db: instead of
    using a temp id, I'm actually assigning a JIT-generated id for a
    mark even if that isn't inserted into the db yet. this has two
    benefits: div ids have meaningful static ids (e.g.
    mark-container-\<\> mark.id) regardless of whether that mark has
    been inserted into the db or not. While doing this, the changeset
    for marks has been udpated to add id as well. This fixes a bunch of
    id-based errors as well.

2.  while doing 1, it came to light that the bindHoverune handlers were
    not handling the draft mark update properly (i.e. not using the
    already existing update function in mark) . it's changed now,
    example of the diff:

    ``` diff
      @impl true
      def handle_event(
            "bindHoveRune",
            %{"binding" => bind = %{"verse_id" => verse_id}},
            %{
              assigns: %{
                kv_verses: verses,
                marks: [%Mark{state: :draft, verse_id: curr_verse_id} = d_mark | marks]
              }
            } = socket
          )
          when is_binary(curr_verse_id) and verse_id != curr_verse_id do
        # binding here blocks the stream from appending to quote
        bind = Draft.bind_node(bind)

        bound_verses =
          verses
           |> then(&put_in(&1[verse_id].binding, bind))
           |> then(&put_in(&1[curr_verse_id].binding, nil))

    +    updated_draft_mark = d_mark |> Mark.update_mark(%{binding: bind, verse_id: verse_id})
    +
         {:noreply,
          socket
          |> mutate_verses(curr_verse_id, bound_verses)
          |> mutate_verses(verse_id, bound_verses)
    -     |> assign(:marks, [%{d_mark | binding: bind, verse_id: verse_id} | marks])}
    +     |> assign(:marks, [updated_draft_mark | marks])}
       end
    ```

3.  add ui state structs: all of the relevant ui states have structs
    that are intended to be static interfaces. this felt better than
    directly keeping state within various sockets and is done with a
    view to remove live components and change them to function
    components wherever possible.

4.  bugfix for `order()`:

    - it had an off-by-one-error
    - shifted it to Vyasa.Sangh.Mark
    - also note that the order shall be 1-indexed instead of 0-indexed
      for human-friendliness

5.  minor fixes:

    1.  fix update<sub>mark</sub> default argument

        ``` diff
        -def update_mark(%Mark{} = draft_mark, opts \\ []) do
        +def update_mark(%Mark{} = draft_mark, opts \\ %{}) do
        ```

1.  In this commit, the marks<sub>ui</sub> is NOT kept by the read
    context module, that's why when I update things by create mark or
    delete mark, the ui state is not preserved and initial, default
    state is seen. This was intentionally done in this commit because
    I'm having problems with duplicate ids for verses for some reason,
    I'll show it in the next commit, so that the problem can be clearly
    seen.

* [BUGGY] keep marks_ui within ReadContext

This is buggy, not sure why there's a duplicate yet.  will come back to
it after lunch

Replication Steps:
1. delete all marks and see there's no error
2. create first mark ==> no error
3. create second mark ==> crashes due to duplicate verse id

Crash dump:

[debug] Replied in 13ms
[error] GenServer #PID<0.8416.0> terminating
** (RuntimeError) found duplicate ID "verse-7d9d588a-34fc-4f19-b974-fc32b49b6a61" for component VyasaWeb.Context.Read.VerseMatrix when rendering template
    (phoenix_live_view 1.0.0-rc.6) lib/phoenix_live_view/diff.ex:634: anonymous fn/5 in Phoenix.LiveView.Diff.render_pending_components/6
    (elixir 1.17.2) lib/enum.ex:2531: Enum."-reduce/3-lists^foldl/2-0-"/3
    (phoenix_live_view 1.0.0-rc.6) lib/phoenix_live_view/diff.ex:631: anonymous fn/4 in Phoenix.LiveView.Diff.render_pending_components/6
    (stdlib 5.2.3) maps.erl:416: :maps.fold_1/4
    (phoenix_live_view 1.0.0-rc.6) lib/phoenix_live_view/diff.ex:625: Phoenix.LiveView.Diff.render_pending_components/6
    (phoenix_live_view 1.0.0-rc.6) lib/phoenix_live_view/diff.ex:217: Phoenix.LiveView.Diff.write_component/4
    (phoenix_live_view 1.0.0-rc.6) lib/phoenix_live_view/channel.ex:662: Phoenix.LiveView.Channel.component_handle/4
    (stdlib 5.2.3) gen_server.erl:1095: :gen_server.try_handle_info/3
    (stdlib 5.2.3) gen_server.erl:1183: :gen_server.handle_msg/6
    (stdlib 5.2.3) proc_lib.erl:251: :proc_lib.wake_up/3
Last message: %Phoenix.Socket.Message{topic: "lv:phx-F_1MH_6F0ciqVqwi", event: "event", payload: %{"cid" => 3, "event" => "createMark", "type" => "form", "value" => "body=how+about+now%2C+any+duplicate%3F"}, ref: "23", join_ref: "4"}
State: %{socket: #Phoenix.LiveView.Socket<id: "phx-F_1MH_6F0ciqVqwi", endpoint: VyasaWeb.Endpoint, view: VyasaWeb.ModeLive.Mediator, parent_pid: nil, root_pid: #PID<0.8416.0>, router: VyasaWeb.Router, assigns: %{mode: %VyasaWeb.ModeLive.UserMode{mode: "read", default_ui_state: %VyasaWeb.ModeLive.UiState{show_media_bridge?: true, show_action_bar?: true}, mode_icon_name: "hero-book-open", quick_actions: [:mark_quote, :bookmark], control_panel_modes: ["discuss"], mode_actions: [:mark_quote, :bookmark], action_bar_actions: [:nav_back, :nav_fwd], action_bar_info_types: nil, action_bar_component: VyasaWeb.MediaLive.MediaBridge, action_bar_component_selector: "media-bridge", control_panel_component: VyasaWeb.ControlPanel, control_panel_component_selector: "control-panel", mode_context_component: VyasaWeb.Context.Read, mode_context_component_selector: "read"}, session: %VyasaWeb.Session{name: "ritesh kumar", id: "IhrQV0ypqg8bHakbvb2bymNF", active: true, sangh: %Vyasa.Sangh.Session{__meta__: #Ecto.Schema.Metadata<:loaded, "sessions">, id: "164eb05d-221a-4939-b180-8394e1a5515f", sheafs: #Ecto.Association.NotLoaded<association :sheafs is not loaded>, inserted_at: ~U[2024-09-27 00:51:48Z], updated_at: ~U[2024-09-27 00:51:48Z]}, last_opened: "2024-09-23T11:03:32.022987Z"}, __changed__: %{}, flash: %{}, locale: "en-GB", url_params: %{"chap_no" => "1", "source_title" => "hanuman_chalisa"}, live_action: :show_verses, ui_state: %VyasaWeb.ModeLive.UiState{show_media_bridge?: true, show_action_bar?: true}, device_type: :desktop, tz: %{timezone: "Asia/Singapore", timezone_offset: 480}}, transport_pid: #PID<0.8403.0>, ...>, components: {%{15 => {VyasaWeb.Context.Read.VerseMatrix, "verse-aa3ad88b-0de1-443e-b471-c08a44e67c61", %{id: "verse-aa3ad88b-0de1-443e-b471-c08a44e67c61", edge: [%{title: "1.10", field: [:body], verseup: {:big, "dn"}}, %{node: %Vyasa.Written.Translation{__meta__: #Ecto.Schema.Metadata<:loaded, "translations">, id: "651676b6-ffc3-41c1-b525-f376989f639e", lang: "en", type: "verses", target: %Vyasa.Written.Translation.Target{id: "dd20a94f-8f34-49f8-8da8-4321cfecf172", title: nil, title_translit: nil, body: "प्रभु चरित्र सुनिबे को रसिया ।\n\nराम लखन सीता मन बसिया ॥८॥", body_meant: nil, body_translit: "prabhu caritra sunibe ko rasiyā .\n\nrāma lakhana sītā mana basiyā ..8..", body_translit_meant: "You feel extremely delighted in listening to Lord Rama’s doings and conduct. Lord Rama, Mother Sita, and Lord Laxmana dwell forever in your heart."}, verse_id: "aa3ad88b-0de1-443e-b471-c08a44e67c61", verse: #Ecto.Association.NotLoaded<association :verse is not loaded>, chapter_no: nil, chapter: #Ecto.Association.NotLoaded<association :chapter is not loaded>, source_id: "63918acd-77a9-451a-b8d1-8d5b73208eae", source: #Ecto.Association.NotLoaded<association :source is not loaded>}, field: [:target, :body_translit], verseup: :mid}, %{node: %Vyasa.Written.Translation{__meta__: #Ecto.Schema.Metadata<:loaded, "translations">, id: "651676b6-ffc3-41c1-b525-f376989f639e", lang: "en", type: "verses", target: %Vyasa.Written.Translation.Target{id: "dd20a94f-8f34-49f8-8da8-4321cfecf172", title: nil, title_translit: nil, body: "प्रभु चरित्र सुनिबे को रसिया ।\n\nराम लखन सीता मन बसिया ॥८॥", body_meant: nil, body_translit: "prabhu caritra sunibe ko rasiyā .\n\nrāma lakhana sītā mana basiyā ..8..", body_translit_meant: "You feel extremely delighted in listening to Lord Rama’s doings and conduct. Lord Rama, Mother Sita, and Lord Laxmana dwell forever in your heart."}, verse_id: "aa3ad88b-0de1-443e-b471-c08a44e67c61", verse: #Ecto.Association.NotLoaded<association :verse is not loaded>, chapter_no: nil, chapter: #Ecto.Association.NotLoaded<association :chapter is not loaded>, source_id: "63918acd-77a9-451a-b8d1-8d5b73208eae", source: #Ecto.Association.NotLoaded<association :source is not loaded>}, field: [:target, :body_translit_meant], verseup: :mid}, %{node: %Vyasa.Written.Translation{__meta__: #Ecto.Schema.Metadata<:loaded, "translations">, id: "651676b6-ffc3-41c1-b525-f376989f639e", lang: "en", type: "verses", target: %Vyasa.Written.Translation.Target{id: "dd20a94f-8f34-49f8-8da8-4321cfecf172", title: nil, title_translit: nil, body: "प्रभु चरित्र सुनिबे को रसिया ।\n\nराम लखन सीता मन बसिया ॥८॥", body_meant: nil, body_translit: "prabhu caritra sunibe ko rasiyā .\n\nrāma lakhana sītā mana basiyā ..8..", body_translit_meant: "You feel extremely delighted in listening to Lord Rama’s doings and conduct. Lord Rama, Mother Sita, and Lord Laxmana dwell forever in your heart."}, verse_id: "aa3ad88b-0de1-443e-b471-c08a44e67c61", verse: #Ecto.Association.NotLoaded<association :verse is not loaded>, chapter_no: nil, chapter: #Ecto.Association.NotLoaded<association :chapter is not loaded>, source_id: "63918acd-77a9-451a-b8d1-8d5b73208eae", source: #Ecto.Association.NotLoaded<association :source is not loaded>}, field: [:target, :body], verseup: :mid}], __changed__: %{}, flash: %{}, marks: [%Vyasa.Sangh.Mark{__meta__: #Ecto.Schema.Metadata<:loaded, "marks">, id: "5dfdb167-6c57-46dd-a0c4-10b52cb03a85", body: "wonderful", order: 2, state: :live, verse_id: nil, sheaf_id: "7f4ab16b-0caf-4009-ba2a-3ddded81d9aa", sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>, binding_id: "001da594-3808-46cf-9b9c-5dfb3559780e", binding: %Vyasa.Adapters.Binding{__meta__: #Ecto.Schema.Metadata<:loaded, "bindings">, id: "001da594-3808-46cf-9b9c-5dfb3559780e", w_type: nil, field_key: ["target", "body_translit_meant"], node_id: nil, verse_id: nil, verse: #Ecto.Association.NotLoaded<association :verse is not loaded>, chapter_no: nil, chapter: #Ecto.Association.NotLoaded<association :chapter is not loaded>, source_id: nil, source: #Ecto.Association.NotLoaded<association :source is not loaded>, translation_id: "97a7a662-a91b-486f-93e8-7ae932d01a1a", translation: #Ecto.Association.NotLoaded<association :translation is not loaded>, sheaf_id: nil, sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>, window: nil}, inserted_at: ~U[2024-10-11 04:31:50Z], updated_at: ~U[2024-10-11 04:31:50Z]}, %Vyasa.Sangh.Mark{__meta__: #Ecto.Schema.Metadata<:loaded, "marks">, id: "273a093d-4f90-40a4-b19a-2f8f7825d201", body: "truncated utc datetime", order: 1, state: :live, verse_id: nil, sheaf_id: "7f4ab16b-0caf-4009-ba2a-3ddded81d9aa", sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>, binding_id: "ef39315b-530c-4841-ba32-86773f451727", binding: %Vyasa.Adapt (truncated)
[debug] MOUNT VyasaWeb.ModeLive.Mediator
  Parameters: %{"chap_no" => "1", "source_title" => "hanuman_chalisa"}
  Session: %{"_csrf_token" => "DJ-RIoXwEzHW82rbb21le_8k"}
[debug] QUERY OK source="sessions" db=3.5ms idle=1690.4ms
SELECT s0."id", s0."inserted_at", s0."updated_at" FROM "sessions" AS s0 WHERE (s0."id" = $1) ["164eb05d-221a-4939-b180-8394e1a5515f"]
↳

* Fix duplicate id issue on verse matrix

* Standardise use of @event_target, cleanups

When using @event_target, the intent is that phx-target values
will be passed around. This must be agnostic to the 2 main ways of
supplying that argument, as a HTML selector, or as a module name (or @myself).
Therefore, we should discourage ourselves from doing format-strings at
the point of the @event_target being supplied as an argument, meaning:

good, because agnostic:
phx-target={@event_target}

bad, because hardcoded:
phx-target={"#" <> @event_target}
* in this case, the event trigger will throw a dom error.

* [Attempt]: Sanitise, defrag orders in marks-list

If this is an anti-pattern, then this commit should be reverted.

* UI fixes: hide buttons on marks when !is_editable?

* Add in stub event handlers to prevent crashes

Temporary stuff, will be addressed in immediate-next PR

* Minor changes

* Toggle edit state for marks content

* Partial implementation of edit marks

the form stuff doesn't exist so it's not wired up yet. To be frank,
im' not sure how to set up a form without it needing to hold state.

* [BUGGY] Wire up form update for edit

this does the following:
1. wires up the form like how we usedd it in createMark
2. actually captures the event properly within the event handler,
everything looks good at that point, even the edit_mark_in_marks
function on inspection looks good
3. the marks is getting assigned to properly because the newly edited
mark content is seen after doing a dom refresh
4. HOWEVER, the print statement at the sheaf_update function DOES NOT
show the correct, updated marks in the sheaf

here's a dump for it for reference

[debug] HANDLE EVENT "editMarkContent" in VyasaWeb.ModeLive.Mediator
  Component: VyasaWeb.Context.Read
  Parameters: %{"mark_id" => "02218551-591f-4450-abbd-a7b7d76fd48e"}
[debug] Replied in 2ms
[debug] HANDLE EVENT "editMarkContent" in VyasaWeb.ModeLive.Mediator
  Component: VyasaWeb.Context.Read
  Parameters: %{"mark_body" => "  testing\n\n\nwhat hte heck", "mark_id" => "02218551-591f-4450-abbd-a7b7d76fd48e"}
>>> UPDATE SHEAF -- SHOULD BE WRITING TO DB NOW: %Vyasa.Sangh.Sheaf{
  __meta__: #Ecto.Schema.Metadata<:loaded, "sheafs">,
  id: "7f4ab16b-0caf-4009-ba2a-3ddded81d9aa",
  body: nil,
  active: true,
  path: %EctoLtree.LabelTree{labels: ["7f4ab16b"]},
  signature: nil,
  traits: ["draft"],
  child_count: 0,
  session_id: "164eb05d-221a-4939-b180-8394e1a5515f",
  session: #Ecto.Association.NotLoaded<association :session is not loaded>,
  parent_id: nil,
  parent: #Ecto.Association.NotLoaded<association :parent is not loaded>,
  marks: [
    %Vyasa.Sangh.Mark{
      __meta__: #Ecto.Schema.Metadata<:loaded, "marks">,
      id: "555eb625-e392-496e-9831-4f4c130be6fd",
      body: "wonderful stuff",
      order: 5,
      state: :live,
      verse_id: nil,
      sheaf_id: "7f4ab16b-0caf-4009-ba2a-3ddded81d9aa",
      sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>,
      binding_id: "072124d0-5e27-4601-832f-35eaa6426879",
      binding: %Vyasa.Adapters.Binding{
        __meta__: #Ecto.Schema.Metadata<:loaded, "bindings">,
        id: "072124d0-5e27-4601-832f-35eaa6426879",
        w_type: nil,
        field_key: ["target", "body_translit_meant"],
        node_id: nil,
        verse_id: nil,
        verse: #Ecto.Association.NotLoaded<association :verse is not loaded>,
        chapter_no: nil,
        chapter: #Ecto.Association.NotLoaded<association :chapter is not loaded>,
        source_id: nil,
        source: #Ecto.Association.NotLoaded<association :source is not loaded>,
        translation_id: "97a7a662-a91b-486f-93e8-7ae932d01a1a",
        translation: #Ecto.Association.NotLoaded<association :translation is not loaded>,
        sheaf_id: nil,
        sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>,
        window: nil
      },
      inserted_at: ~U[2024-10-12 08:46:54Z],
      updated_at: ~U[2024-10-12 08:46:54Z]
    },
    %Vyasa.Sangh.Mark{
      __meta__: #Ecto.Schema.Metadata<:loaded, "marks">,
      id: "b22a5661-8268-4875-be26-a12256414136",
      body: nil,
      order: 5,
      state: :draft,
      verse_id: nil,
      sheaf_id: "7f4ab16b-0caf-4009-ba2a-3ddded81d9aa",
      sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>,
      binding_id: "90e18044-73b2-4ede-a149-a381de893b9f",
      binding: %Vyasa.Adapters.Binding{
        __meta__: #Ecto.Schema.Metadata<:loaded, "bindings">,
        id: "90e18044-73b2-4ede-a149-a381de893b9f",
        w_type: nil,
        field_key: ["target", "body_translit_meant"],
        node_id: nil,
        verse_id: nil,
        verse: #Ecto.Association.NotLoaded<association :verse is not loaded>,
        chapter_no: nil,
        chapter: #Ecto.Association.NotLoaded<association :chapter is not loaded>,
        source_id: nil,
        source: #Ecto.Association.NotLoaded<association :source is not loaded>,
        translation_id: "fc80709a-39dc-4b9c-95c3-1d64ce818302",
        translation: #Ecto.Association.NotLoaded<association :translation is not loaded>,
        sheaf_id: nil,
        sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>,
        window: nil
      },
      inserted_at: ~U[2024-10-12 09:52:40Z],
      updated_at: ~U[2024-10-12 09:52:40Z]
    },
    %Vyasa.Sangh.Mark{
      __meta__: #Ecto.Schema.Metadata<:loaded, "marks">,
      id: "8af43833-575c-4eb8-83b1-eb4e58509e4c",
      body: nil,
      order: 4,
      state: :draft,
      verse_id: nil,
      sheaf_id: "7f4ab16b-0caf-4009-ba2a-3ddded81d9aa",
      sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>,
      binding_id: "23b70937-ed81-47fe-a560-ee14287bff7d",
      binding: %Vyasa.Adapters.Binding{
        __meta__: #Ecto.Schema.Metadata<:loaded, "bindings">,
        id: "23b70937-ed81-47fe-a560-ee14287bff7d",
        w_type: nil,
        field_key: ["target", "body_translit_meant"],
        node_id: nil,
        verse_id: nil,
        verse: #Ecto.Association.NotLoaded<association :verse is not loaded>,
        chapter_no: nil,
        chapter: #Ecto.Association.NotLoaded<association :chapter is not loaded>,
        source_id: nil,
        source: #Ecto.Association.NotLoaded<association :source is not loaded>,
        translation_id: "97a7a662-a91b-486f-93e8-7ae932d01a1a",
        translation: #Ecto.Association.NotLoaded<association :translation is not loaded>,
        sheaf_id: nil,
        sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>,
        window: nil
      },
      inserted_at: ~U[2024-10-12 09:46:13Z],
      updated_at: ~U[2024-10-12 09:46:13Z]
    },
    %Vyasa.Sangh.Mark{
      __meta__: #Ecto.Schema.Metadata<:loaded, "marks">,
      id: "c7ad47e6-629d-4382-936d-64d757772c4e",
      body: nil,
      order: 3,
      state: :draft,
      verse_id: nil,
      sheaf_id: "7f4ab16b-0caf-4009-ba2a-3ddded81d9aa",
      sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>,
      binding_id: "d5758230-7966-4f9b-8c16-ae13998cd71b",
      binding: %Vyasa.Adapters.Binding{
        __meta__: #Ecto.Schema.Metadata<:loaded, "bindings">,
        id: "d5758230-7966-4f9b-8c16-ae13998cd71b",
        w_type: nil,
        field_key: ["target", "body_translit_meant"],
        node_id: nil,
        verse_id: nil,
        verse: #Ecto.Association.NotLoaded<association :verse is not loaded>,
        chapter_no: nil,
        chapter: #Ecto.Association.NotLoaded<association :chapter is not loaded>,
        source_id: nil,
        source: #Ecto.Association.NotLoaded<association :source is not loaded>,
        translation_id: "fc80709a-39dc-4b9c-95c3-1d64ce818302",
        translation: #Ecto.Association.NotLoaded<association :translation is not loaded>,
        sheaf_id: nil,
        sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>,
        window: nil
      },
      inserted_at: ~U[2024-10-12 09:44:09Z],
      updated_at: ~U[2024-10-12 09:44:09Z]
    },
    %Vyasa.Sangh.Mark{
      __meta__: #Ecto.Schema.Metadata<:loaded, "marks">,
      id: "02218551-591f-4450-abbd-a7b7d76fd48e",
      body: "testing",
      order: 2,
      state: :live,
      verse_id: nil,
      sheaf_id: "7f4ab16b-0caf-4009-ba2a-3ddded81d9aa",
      sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>,
      binding_id: "19ffdc82-a5d8-49c3-8b01-1559736dad80",
      binding: %Vyasa.Adapters.Binding{
        __meta__: #Ecto.Schema.Metadata<:loaded, "bindings">,
        id: "19ffdc82-a5d8-49c3-8b01-1559736dad80",
        w_type: nil,
        field_key: ["target", "body_translit_meant"],
        node_id: nil,
        verse_id: nil,
        verse: #Ecto.Association.NotLoaded<association :verse is not loaded>,
        chapter_no: nil,
        chapter: #Ecto.Association.NotLoaded<association :chapter is not loaded>,
        source_id: nil,
        source: #Ecto.Association.NotLoaded<association :source is not loaded>,
        translation_id: "fc80709a-39dc-4b9c-95c3-1d64ce818302",
        translation: #Ecto.Association.NotLoaded<association :translation is not loaded>,
        sheaf_id: nil,
        sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>,
        window: nil
      },
      inserted_at: ~U[2024-10-12 09:43:19Z],
      updated_at: ~U[2024-10-12 09:43:19Z]
    },
    %Vyasa.Sangh.Mark{
      __meta__: #Ecto.Schema.Metadata<:loaded, "marks">,
      id: "90c6036a-9bd1-4b65-82d5-f121ec4d7867",
      body: nil,
      order: 2,
      state: :draft,
      verse_id: nil,
      sheaf_id: "7f4ab16b-0caf-4009-ba2a-3ddded81d9aa",
      sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>,
      binding_id: "b92f990d-99a2-4f04-a2d4-d1135021ee8c",
      binding: %Vyasa.Adapters.Binding{
        __meta__: #Ecto.Schema.Metadata<:loaded, "bindings">,
        id: "b92f990d-99a2-4f04-a2d4-d1135021ee8c",
        w_type: nil,
        field_key: ["target", "body_translit_meant"],
        node_id: nil,
        verse_id: nil,
        verse: #Ecto.Association.NotLoaded<association :verse is not loaded>,
        chapter_no: nil,
        chapter: #Ecto.Association.NotLoaded<association :chapter is not loaded>,
        source_id: nil,
        source: #Ecto.Association.NotLoaded<association :source is not loaded>,
        translation_id: "97a7a662-a91b-486f-93e8-7ae932d01a1a",
        translation: #Ecto.Association.NotLoaded<association :translation is not loaded>,
        sheaf_id: nil,
        sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>,
        window: nil
      },
      inserted_at: ~U[2024-10-11 09:03:00Z],
      updated_at: ~U[2024-10-11 09:03:00Z]
    }
  ],
  inserted_at: ~N[2024-09-27 00:51:48],
  updated_at: ~N[2024-09-27 00:51:48]
}
[debug] Replied in 81ms
[debug] HANDLE EVENT "verses::focus_toggle_on_quick_mark_drafting" in VyasaWeb.ModeLive.Mediator
  Component: VyasaWeb.Context.Read
  Parameters: %{"is_focusing?" => false, "value" => ""}
[debug] Replied in 129µs
iex([email protected])17>

* marks order force

* old man mark is not feeling so good

* ReWrite how marks get initialised @ :show_verse (#119)

* Minor change in fn signature

* Add init_draft_reflector()

---------

Co-authored-by: ks0m1c_dharma <[email protected]>

* Minor changes

* Add a generic modal wrapper (#120)

* Add generic debug dump component

This makes life easy when wiring things up

* Rename namespace for Context.Read.*

* Groundwork: add discuss component w sheafs

* Init Context.Components mod for common components

* Add skeletons for Sheaf Container

Container managers sheaf state within itself.
Should actually make the verse-matrix use this container, sometime.

* Minor changes, add some TODOs to share

explicit todos

Minor change

* Add live component EditableMarkDisplay

* Add UI improvements to EditableMarkDisplay

The edit button on quick draft should only be seen when the dropdown is
expanded and all the marks can be seen. The general pattern I'm trying
to follow is that buttons should only be shown when an action makes
sense. So here, if the user can't even see the marks currently
accumulating, then the user shouldn't have the chance to edit any marks.

Notice that the EditableMarkDisplay is a live_component that is a child
of a function component (collapsible_marks_display). This is so that it can keep its own state and
do it's own event-handling. I'm not sure if this is pattern-breaking.
A reference to the actual parent live_component that calls collapsible_marks_display
will always be there in case there's a need for the parent to handle
any particular events. So comms b/w live_components is still going to be
via phx-target values.

* Change <input/> -> <textarea/> fr quick_draft_form

* Add tailwind config for custom svg icons

not sure how the scaling for this works, seems like i can't just put in
the class="h-5 w-5" to do the scaling

* Let custom svg be scalable

* Subtly shift the ping indicator to control panel

* Marks ordering in Sheaf and L-Trees  (#114)

* do sheafs grow on trees

* sangh session dealing with lineage

* Solve initial order problem

* fix: ensure non-null id used @ EditableMarkDisplay

---------

Co-authored-by: ks0m1c_dharma <[email protected]>

* Trigger Diff

* TOMBSTONING

* Fix bugs and revert ui for read_mode:delete marks

1.  JIT generate id for marks yet to be inserted to the db: instead of
    using a temp id, I'm actually assigning a JIT-generated id for a
    mark even if that isn't inserted into the db yet. this has two
    benefits: div ids have meaningful static ids (e.g.
    mark-container-\<\> mark.id) regardless of whether that mark has
    been inserted into the db or not. While doing this, the changeset
    for marks has been udpated to add id as well. This fixes a bunch of
    id-based errors as well.

2.  while doing 1, it came to light that the bindHoverune handlers were
    not handling the draft mark update properly (i.e. not using the
    already existing update function in mark) . it's changed now,
    example of the diff:

    ``` diff
      @impl true
      def handle_event(
            "bindHoveRune",
            %{"binding" => bind = %{"verse_id" => verse_id}},
            %{
              assigns: %{
                kv_verses: verses,
                marks: [%Mark{state: :draft, verse_id: curr_verse_id} = d_mark | marks]
              }
            } = socket
          )
          when is_binary(curr_verse_id) and verse_id != curr_verse_id do
        # binding here blocks the stream from appending to quote
        bind = Draft.bind_node(bind)

        bound_verses =
          verses
           |> then(&put_in(&1[verse_id].binding, bind))
           |> then(&put_in(&1[curr_verse_id].binding, nil))

    +    updated_draft_mark = d_mark |> Mark.update_mark(%{binding: bind, verse_id: verse_id})
    +
         {:noreply,
          socket
          |> mutate_verses(curr_verse_id, bound_verses)
          |> mutate_verses(verse_id, bound_verses)
    -     |> assign(:marks, [%{d_mark | binding: bind, verse_id: verse_id} | marks])}
    +     |> assign(:marks, [updated_draft_mark | marks])}
       end
    ```

3.  add ui state structs: all of the relevant ui states have structs
    that are intended to be static interfaces. this felt better than
    directly keeping state within various sockets and is done with a
    view to remove live components and change them to function
    components wherever possible.

4.  bugfix for `order()`:

    - it had an off-by-one-error
    - shifted it to Vyasa.Sangh.Mark
    - also note that the order shall be 1-indexed instead of 0-indexed
      for human-friendliness

5.  minor fixes:

    1.  fix update<sub>mark</sub> default argument

        ``` diff
        -def update_mark(%Mark{} = draft_mark, opts \\ []) do
        +def update_mark(%Mark{} = draft_mark, opts \\ %{}) do
        ```

1.  In this commit, the marks<sub>ui</sub> is NOT kept by the read
    context module, that's why when I update things by create mark or
    delete mark, the ui state is not preserved and initial, default
    state is seen. This was intentionally done in this commit because
    I'm having problems with duplicate ids for verses for some reason,
    I'll show it in the next commit, so that the problem can be clearly
    seen.

* [BUGGY] keep marks_ui within ReadContext

This is buggy, not sure why there's a duplicate yet.  will come back to
it after lunch

Replication Steps:
1. delete all marks and see there's no error
2. create first mark ==> no error
3. create second mark ==> crashes due to duplicate verse id

Crash dump:

[debug] Replied in 13ms
[error] GenServer #PID<0.8416.0> terminating
** (RuntimeError) found duplicate ID "verse-7d9d588a-34fc-4f19-b974-fc32b49b6a61" for component VyasaWeb.Context.Read.VerseMatrix when rendering template
    (phoenix_live_view 1.0.0-rc.6) lib/phoenix_live_view/diff.ex:634: anonymous fn/5 in Phoenix.LiveView.Diff.render_pending_components/6
    (elixir 1.17.2) lib/enum.ex:2531: Enum."-reduce/3-lists^foldl/2-0-"/3
    (phoenix_live_view 1.0.0-rc.6) lib/phoenix_live_view/diff.ex:631: anonymous fn/4 in Phoenix.LiveView.Diff.render_pending_components/6
    (stdlib 5.2.3) maps.erl:416: :maps.fold_1/4
    (phoenix_live_view 1.0.0-rc.6) lib/phoenix_live_view/diff.ex:625: Phoenix.LiveView.Diff.render_pending_components/6
    (phoenix_live_view 1.0.0-rc.6) lib/phoenix_live_view/diff.ex:217: Phoenix.LiveView.Diff.write_component/4
    (phoenix_live_view 1.0.0-rc.6) lib/phoenix_live_view/channel.ex:662: Phoenix.LiveView.Channel.component_handle/4
    (stdlib 5.2.3) gen_server.erl:1095: :gen_server.try_handle_info/3
    (stdlib 5.2.3) gen_server.erl:1183: :gen_server.handle_msg/6
    (stdlib 5.2.3) proc_lib.erl:251: :proc_lib.wake_up/3
Last message: %Phoenix.Socket.Message{topic: "lv:phx-F_1MH_6F0ciqVqwi", event: "event", payload: %{"cid" => 3, "event" => "createMark", "type" => "form", "value" => "body=how+about+now%2C+any+duplicate%3F"}, ref: "23", join_ref: "4"}
State: %{socket: #Phoenix.LiveView.Socket<id: "phx-F_1MH_6F0ciqVqwi", endpoint: VyasaWeb.Endpoint, view: VyasaWeb.ModeLive.Mediator, parent_pid: nil, root_pid: #PID<0.8416.0>, router: VyasaWeb.Router, assigns: %{mode: %VyasaWeb.ModeLive.UserMode{mode: "read", default_ui_state: %VyasaWeb.ModeLive.UiState{show_media_bridge?: true, show_action_bar?: true}, mode_icon_name: "hero-book-open", quick_actions: [:mark_quote, :bookmark], control_panel_modes: ["discuss"], mode_actions: [:mark_quote, :bookmark], action_bar_actions: [:nav_back, :nav_fwd], action_bar_info_types: nil, action_bar_component: VyasaWeb.MediaLive.MediaBridge, action_bar_component_selector: "media-bridge", control_panel_component: VyasaWeb.ControlPanel, control_panel_component_selector: "control-panel", mode_context_component: VyasaWeb.Context.Read, mode_context_component_selector: "read"}, session: %VyasaWeb.Session{name: "ritesh kumar", id: "IhrQV0ypqg8bHakbvb2bymNF", active: true, sangh: %Vyasa.Sangh.Session{__meta__: #Ecto.Schema.Metadata<:loaded, "sessions">, id: "164eb05d-221a-4939-b180-8394e1a5515f", sheafs: #Ecto.Association.NotLoaded<association :sheafs is not loaded>, inserted_at: ~U[2024-09-27 00:51:48Z], updated_at: ~U[2024-09-27 00:51:48Z]}, last_opened: "2024-09-23T11:03:32.022987Z"}, __changed__: %{}, flash: %{}, locale: "en-GB", url_params: %{"chap_no" => "1", "source_title" => "hanuman_chalisa"}, live_action: :show_verses, ui_state: %VyasaWeb.ModeLive.UiState{show_media_bridge?: true, show_action_bar?: true}, device_type: :desktop, tz: %{timezone: "Asia/Singapore", timezone_offset: 480}}, transport_pid: #PID<0.8403.0>, ...>, components: {%{15 => {VyasaWeb.Context.Read.VerseMatrix, "verse-aa3ad88b-0de1-443e-b471-c08a44e67c61", %{id: "verse-aa3ad88b-0de1-443e-b471-c08a44e67c61", edge: [%{title: "1.10", field: [:body], verseup: {:big, "dn"}}, %{node: %Vyasa.Written.Translation{__meta__: #Ecto.Schema.Metadata<:loaded, "translations">, id: "651676b6-ffc3-41c1-b525-f376989f639e", lang: "en", type: "verses", target: %Vyasa.Written.Translation.Target{id: "dd20a94f-8f34-49f8-8da8-4321cfecf172", title: nil, title_translit: nil, body: "प्रभु चरित्र सुनिबे को रसिया ।\n\nराम लखन सीता मन बसिया ॥८॥", body_meant: nil, body_translit: "prabhu caritra sunibe ko rasiyā .\n\nrāma lakhana sītā mana basiyā ..8..", body_translit_meant: "You feel extremely delighted in listening to Lord Rama’s doings and conduct. Lord Rama, Mother Sita, and Lord Laxmana dwell forever in your heart."}, verse_id: "aa3ad88b-0de1-443e-b471-c08a44e67c61", verse: #Ecto.Association.NotLoaded<association :verse is not loaded>, chapter_no: nil, chapter: #Ecto.Association.NotLoaded<association :chapter is not loaded>, source_id: "63918acd-77a9-451a-b8d1-8d5b73208eae", source: #Ecto.Association.NotLoaded<association :source is not loaded>}, field: [:target, :body_translit], verseup: :mid}, %{node: %Vyasa.Written.Translation{__meta__: #Ecto.Schema.Metadata<:loaded, "translations">, id: "651676b6-ffc3-41c1-b525-f376989f639e", lang: "en", type: "verses", target: %Vyasa.Written.Translation.Target{id: "dd20a94f-8f34-49f8-8da8-4321cfecf172", title: nil, title_translit: nil, body: "प्रभु चरित्र सुनिबे को रसिया ।\n\nराम लखन सीता मन बसिया ॥८॥", body_meant: nil, body_translit: "prabhu caritra sunibe ko rasiyā .\n\nrāma lakhana sītā mana basiyā ..8..", body_translit_meant: "You feel extremely delighted in listening to Lord Rama’s doings and conduct. Lord Rama, Mother Sita, and Lord Laxmana dwell forever in your heart."}, verse_id: "aa3ad88b-0de1-443e-b471-c08a44e67c61", verse: #Ecto.Association.NotLoaded<association :verse is not loaded>, chapter_no: nil, chapter: #Ecto.Association.NotLoaded<association :chapter is not loaded>, source_id: "63918acd-77a9-451a-b8d1-8d5b73208eae", source: #Ecto.Association.NotLoaded<association :source is not loaded>}, field: [:target, :body_translit_meant], verseup: :mid}, %{node: %Vyasa.Written.Translation{__meta__: #Ecto.Schema.Metadata<:loaded, "translations">, id: "651676b6-ffc3-41c1-b525-f376989f639e", lang: "en", type: "verses", target: %Vyasa.Written.Translation.Target{id: "dd20a94f-8f34-49f8-8da8-4321cfecf172", title: nil, title_translit: nil, body: "प्रभु चरित्र सुनिबे को रसिया ।\n\nराम लखन सीता मन बसिया ॥८॥", body_meant: nil, body_translit: "prabhu caritra sunibe ko rasiyā .\n\nrāma lakhana sītā mana basiyā ..8..", body_translit_meant: "You feel extremely delighted in listening to Lord Rama’s doings and conduct. Lord Rama, Mother Sita, and Lord Laxmana dwell forever in your heart."}, verse_id: "aa3ad88b-0de1-443e-b471-c08a44e67c61", verse: #Ecto.Association.NotLoaded<association :verse is not loaded>, chapter_no: nil, chapter: #Ecto.Association.NotLoaded<association :chapter is not loaded>, source_id: "63918acd-77a9-451a-b8d1-8d5b73208eae", source: #Ecto.Association.NotLoaded<association :source is not loaded>}, field: [:target, :body], verseup: :mid}], __changed__: %{}, flash: %{}, marks: [%Vyasa.Sangh.Mark{__meta__: #Ecto.Schema.Metadata<:loaded, "marks">, id: "5dfdb167-6c57-46dd-a0c4-10b52cb03a85", body: "wonderful", order: 2, state: :live, verse_id: nil, sheaf_id: "7f4ab16b-0caf-4009-ba2a-3ddded81d9aa", sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>, binding_id: "001da594-3808-46cf-9b9c-5dfb3559780e", binding: %Vyasa.Adapters.Binding{__meta__: #Ecto.Schema.Metadata<:loaded, "bindings">, id: "001da594-3808-46cf-9b9c-5dfb3559780e", w_type: nil, field_key: ["target", "body_translit_meant"], node_id: nil, verse_id: nil, verse: #Ecto.Association.NotLoaded<association :verse is not loaded>, chapter_no: nil, chapter: #Ecto.Association.NotLoaded<association :chapter is not loaded>, source_id: nil, source: #Ecto.Association.NotLoaded<association :source is not loaded>, translation_id: "97a7a662-a91b-486f-93e8-7ae932d01a1a", translation: #Ecto.Association.NotLoaded<association :translation is not loaded>, sheaf_id: nil, sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>, window: nil}, inserted_at: ~U[2024-10-11 04:31:50Z], updated_at: ~U[2024-10-11 04:31:50Z]}, %Vyasa.Sangh.Mark{__meta__: #Ecto.Schema.Metadata<:loaded, "marks">, id: "273a093d-4f90-40a4-b19a-2f8f7825d201", body: "truncated utc datetime", order: 1, state: :live, verse_id: nil, sheaf_id: "7f4ab16b-0caf-4009-ba2a-3ddded81d9aa", sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>, binding_id: "ef39315b-530c-4841-ba32-86773f451727", binding: %Vyasa.Adapt (truncated)
[debug] MOUNT VyasaWeb.ModeLive.Mediator
  Parameters: %{"chap_no" => "1", "source_title" => "hanuman_chalisa"}
  Session: %{"_csrf_token" => "DJ-RIoXwEzHW82rbb21le_8k"}
[debug] QUERY OK source="sessions" db=3.5ms idle=1690.4ms
SELECT s0."id", s0."inserted_at", s0."updated_at" FROM "sessions" AS s0 WHERE (s0."id" = $1) ["164eb05d-221a-4939-b180-8394e1a5515f"]
↳

* Fix duplicate id issue on verse matrix

* Standardise use of @event_target, cleanups

When using @event_target, the intent is that phx-target values
will be passed around. This must be agnostic to the 2 main ways of
supplying that argument, as a HTML selector, or as a module name (or @myself).
Therefore, we should discourage ourselves from doing format-strings at
the point of the @event_target being supplied as an argument, meaning:

good, because agnostic:
phx-target={@event_target}

bad, because hardcoded:
phx-target={"#" <> @event_target}
* in this case, the event trigger will throw a dom error.

…
* Add generic debug dump component

This makes life easy when wiring things up

* Rename namespace for Context.Read.*

* Groundwork: add discuss component w sheafs

* Init Context.Components mod for common components

* Add skeletons for Sheaf Container

Container managers sheaf state within itself.
Should actually make the verse-matrix use this container, sometime.

* Minor changes, add some TODOs to share

explicit todos

Minor change

* Add live component EditableMarkDisplay

* Add UI improvements to EditableMarkDisplay

The edit button on quick draft should only be seen when the dropdown is
expanded and all the marks can be seen. The general pattern I'm trying
to follow is that buttons should only be shown when an action makes
sense. So here, if the user can't even see the marks currently
accumulating, then the user shouldn't have the chance to edit any marks.

Notice that the EditableMarkDisplay is a live_component that is a child
of a function component (collapsible_marks_display). This is so that it can keep its own state and
do it's own event-handling. I'm not sure if this is pattern-breaking.
A reference to the actual parent live_component that calls collapsible_marks_display
will always be there in case there's a need for the parent to handle
any particular events. So comms b/w live_components is still going to be
via phx-target values.

* Change <input/> -> <textarea/> fr quick_draft_form

* Add tailwind config for custom svg icons

not sure how the scaling for this works, seems like i can't just put in
the class="h-5 w-5" to do the scaling

* Let custom svg be scalable

* Subtly shift the ping indicator to control panel

* Marks ordering in Sheaf and L-Trees  (#114)

* do sheafs grow on trees

* sangh session dealing with lineage

* Solve initial order problem

* fix: ensure non-null id used @ EditableMarkDisplay

---------

Co-authored-by: ks0m1c_dharma <[email protected]>

* Trigger Diff

* TOMBSTONING

* Fix bugs and revert ui for read_mode:delete marks

1.  JIT generate id for marks yet to be inserted to the db: instead of
    using a temp id, I'm actually assigning a JIT-generated id for a
    mark even if that isn't inserted into the db yet. this has two
    benefits: div ids have meaningful static ids (e.g.
    mark-container-\<\> mark.id) regardless of whether that mark has
    been inserted into the db or not. While doing this, the changeset
    for marks has been udpated to add id as well. This fixes a bunch of
    id-based errors as well.

2.  while doing 1, it came to light that the bindHoverune handlers were
    not handling the draft mark update properly (i.e. not using the
    already existing update function in mark) . it's changed now,
    example of the diff:

    ``` diff
      @impl true
      def handle_event(
            "bindHoveRune",
            %{"binding" => bind = %{"verse_id" => verse_id}},
            %{
              assigns: %{
                kv_verses: verses,
                marks: [%Mark{state: :draft, verse_id: curr_verse_id} = d_mark | marks]
              }
            } = socket
          )
          when is_binary(curr_verse_id) and verse_id != curr_verse_id do
        # binding here blocks the stream from appending to quote
        bind = Draft.bind_node(bind)

        bound_verses =
          verses
           |> then(&put_in(&1[verse_id].binding, bind))
           |> then(&put_in(&1[curr_verse_id].binding, nil))

    +    updated_draft_mark = d_mark |> Mark.update_mark(%{binding: bind, verse_id: verse_id})
    +
         {:noreply,
          socket
          |> mutate_verses(curr_verse_id, bound_verses)
          |> mutate_verses(verse_id, bound_verses)
    -     |> assign(:marks, [%{d_mark | binding: bind, verse_id: verse_id} | marks])}
    +     |> assign(:marks, [updated_draft_mark | marks])}
       end
    ```

3.  add ui state structs: all of the relevant ui states have structs
    that are intended to be static interfaces. this felt better than
    directly keeping state within various sockets and is done with a
    view to remove live components and change them to function
    components wherever possible.

4.  bugfix for `order()`:

    - it had an off-by-one-error
    - shifted it to Vyasa.Sangh.Mark
    - also note that the order shall be 1-indexed instead of 0-indexed
      for human-friendliness

5.  minor fixes:

    1.  fix update<sub>mark</sub> default argument

        ``` diff
        -def update_mark(%Mark{} = draft_mark, opts \\ []) do
        +def update_mark(%Mark{} = draft_mark, opts \\ %{}) do
        ```

1.  In this commit, the marks<sub>ui</sub> is NOT kept by the read
    context module, that's why when I update things by create mark or
    delete mark, the ui state is not preserved and initial, default
    state is seen. This was intentionally done in this commit because
    I'm having problems with duplicate ids for verses for some reason,
    I'll show it in the next commit, so that the problem can be clearly
    seen.

* [BUGGY] keep marks_ui within ReadContext

This is buggy, not sure why there's a duplicate yet.  will come back to
it after lunch

Replication Steps:
1. delete all marks and see there's no error
2. create first mark ==> no error
3. create second mark ==> crashes due to duplicate verse id

Crash dump:

[debug] Replied in 13ms
[error] GenServer #PID<0.8416.0> terminating
** (RuntimeError) found duplicate ID "verse-7d9d588a-34fc-4f19-b974-fc32b49b6a61" for component VyasaWeb.Context.Read.VerseMatrix when rendering template
    (phoenix_live_view 1.0.0-rc.6) lib/phoenix_live_view/diff.ex:634: anonymous fn/5 in Phoenix.LiveView.Diff.render_pending_components/6
    (elixir 1.17.2) lib/enum.ex:2531: Enum."-reduce/3-lists^foldl/2-0-"/3
    (phoenix_live_view 1.0.0-rc.6) lib/phoenix_live_view/diff.ex:631: anonymous fn/4 in Phoenix.LiveView.Diff.render_pending_components/6
    (stdlib 5.2.3) maps.erl:416: :maps.fold_1/4
    (phoenix_live_view 1.0.0-rc.6) lib/phoenix_live_view/diff.ex:625: Phoenix.LiveView.Diff.render_pending_components/6
    (phoenix_live_view 1.0.0-rc.6) lib/phoenix_live_view/diff.ex:217: Phoenix.LiveView.Diff.write_component/4
    (phoenix_live_view 1.0.0-rc.6) lib/phoenix_live_view/channel.ex:662: Phoenix.LiveView.Channel.component_handle/4
    (stdlib 5.2.3) gen_server.erl:1095: :gen_server.try_handle_info/3
    (stdlib 5.2.3) gen_server.erl:1183: :gen_server.handle_msg/6
    (stdlib 5.2.3) proc_lib.erl:251: :proc_lib.wake_up/3
Last message: %Phoenix.Socket.Message{topic: "lv:phx-F_1MH_6F0ciqVqwi", event: "event", payload: %{"cid" => 3, "event" => "createMark", "type" => "form", "value" => "body=how+about+now%2C+any+duplicate%3F"}, ref: "23", join_ref: "4"}
State: %{socket: #Phoenix.LiveView.Socket<id: "phx-F_1MH_6F0ciqVqwi", endpoint: VyasaWeb.Endpoint, view: VyasaWeb.ModeLive.Mediator, parent_pid: nil, root_pid: #PID<0.8416.0>, router: VyasaWeb.Router, assigns: %{mode: %VyasaWeb.ModeLive.UserMode{mode: "read", default_ui_state: %VyasaWeb.ModeLive.UiState{show_media_bridge?: true, show_action_bar?: true}, mode_icon_name: "hero-book-open", quick_actions: [:mark_quote, :bookmark], control_panel_modes: ["discuss"], mode_actions: [:mark_quote, :bookmark], action_bar_actions: [:nav_back, :nav_fwd], action_bar_info_types: nil, action_bar_component: VyasaWeb.MediaLive.MediaBridge, action_bar_component_selector: "media-bridge", control_panel_component: VyasaWeb.ControlPanel, control_panel_component_selector: "control-panel", mode_context_component: VyasaWeb.Context.Read, mode_context_component_selector: "read"}, session: %VyasaWeb.Session{name: "ritesh kumar", id: "IhrQV0ypqg8bHakbvb2bymNF", active: true, sangh: %Vyasa.Sangh.Session{__meta__: #Ecto.Schema.Metadata<:loaded, "sessions">, id: "164eb05d-221a-4939-b180-8394e1a5515f", sheafs: #Ecto.Association.NotLoaded<association :sheafs is not loaded>, inserted_at: ~U[2024-09-27 00:51:48Z], updated_at: ~U[2024-09-27 00:51:48Z]}, last_opened: "2024-09-23T11:03:32.022987Z"}, __changed__: %{}, flash: %{}, locale: "en-GB", url_params: %{"chap_no" => "1", "source_title" => "hanuman_chalisa"}, live_action: :show_verses, ui_state: %VyasaWeb.ModeLive.UiState{show_media_bridge?: true, show_action_bar?: true}, device_type: :desktop, tz: %{timezone: "Asia/Singapore", timezone_offset: 480}}, transport_pid: #PID<0.8403.0>, ...>, components: {%{15 => {VyasaWeb.Context.Read.VerseMatrix, "verse-aa3ad88b-0de1-443e-b471-c08a44e67c61", %{id: "verse-aa3ad88b-0de1-443e-b471-c08a44e67c61", edge: [%{title: "1.10", field: [:body], verseup: {:big, "dn"}}, %{node: %Vyasa.Written.Translation{__meta__: #Ecto.Schema.Metadata<:loaded, "translations">, id: "651676b6-ffc3-41c1-b525-f376989f639e", lang: "en", type: "verses", target: %Vyasa.Written.Translation.Target{id: "dd20a94f-8f34-49f8-8da8-4321cfecf172", title: nil, title_translit: nil, body: "प्रभु चरित्र सुनिबे को रसिया ।\n\nराम लखन सीता मन बसिया ॥८॥", body_meant: nil, body_translit: "prabhu caritra sunibe ko rasiyā .\n\nrāma lakhana sītā mana basiyā ..8..", body_translit_meant: "You feel extremely delighted in listening to Lord Rama’s doings and conduct. Lord Rama, Mother Sita, and Lord Laxmana dwell forever in your heart."}, verse_id: "aa3ad88b-0de1-443e-b471-c08a44e67c61", verse: #Ecto.Association.NotLoaded<association :verse is not loaded>, chapter_no: nil, chapter: #Ecto.Association.NotLoaded<association :chapter is not loaded>, source_id: "63918acd-77a9-451a-b8d1-8d5b73208eae", source: #Ecto.Association.NotLoaded<association :source is not loaded>}, field: [:target, :body_translit], verseup: :mid}, %{node: %Vyasa.Written.Translation{__meta__: #Ecto.Schema.Metadata<:loaded, "translations">, id: "651676b6-ffc3-41c1-b525-f376989f639e", lang: "en", type: "verses", target: %Vyasa.Written.Translation.Target{id: "dd20a94f-8f34-49f8-8da8-4321cfecf172", title: nil, title_translit: nil, body: "प्रभु चरित्र सुनिबे को रसिया ।\n\nराम लखन सीता मन बसिया ॥८॥", body_meant: nil, body_translit: "prabhu caritra sunibe ko rasiyā .\n\nrāma lakhana sītā mana basiyā ..8..", body_translit_meant: "You feel extremely delighted in listening to Lord Rama’s doings and conduct. Lord Rama, Mother Sita, and Lord Laxmana dwell forever in your heart."}, verse_id: "aa3ad88b-0de1-443e-b471-c08a44e67c61", verse: #Ecto.Association.NotLoaded<association :verse is not loaded>, chapter_no: nil, chapter: #Ecto.Association.NotLoaded<association :chapter is not loaded>, source_id: "63918acd-77a9-451a-b8d1-8d5b73208eae", source: #Ecto.Association.NotLoaded<association :source is not loaded>}, field: [:target, :body_translit_meant], verseup: :mid}, %{node: %Vyasa.Written.Translation{__meta__: #Ecto.Schema.Metadata<:loaded, "translations">, id: "651676b6-ffc3-41c1-b525-f376989f639e", lang: "en", type: "verses", target: %Vyasa.Written.Translation.Target{id: "dd20a94f-8f34-49f8-8da8-4321cfecf172", title: nil, title_translit: nil, body: "प्रभु चरित्र सुनिबे को रसिया ।\n\nराम लखन सीता मन बसिया ॥८॥", body_meant: nil, body_translit: "prabhu caritra sunibe ko rasiyā .\n\nrāma lakhana sītā mana basiyā ..8..", body_translit_meant: "You feel extremely delighted in listening to Lord Rama’s doings and conduct. Lord Rama, Mother Sita, and Lord Laxmana dwell forever in your heart."}, verse_id: "aa3ad88b-0de1-443e-b471-c08a44e67c61", verse: #Ecto.Association.NotLoaded<association :verse is not loaded>, chapter_no: nil, chapter: #Ecto.Association.NotLoaded<association :chapter is not loaded>, source_id: "63918acd-77a9-451a-b8d1-8d5b73208eae", source: #Ecto.Association.NotLoaded<association :source is not loaded>}, field: [:target, :body], verseup: :mid}], __changed__: %{}, flash: %{}, marks: [%Vyasa.Sangh.Mark{__meta__: #Ecto.Schema.Metadata<:loaded, "marks">, id: "5dfdb167-6c57-46dd-a0c4-10b52cb03a85", body: "wonderful", order: 2, state: :live, verse_id: nil, sheaf_id: "7f4ab16b-0caf-4009-ba2a-3ddded81d9aa", sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>, binding_id: "001da594-3808-46cf-9b9c-5dfb3559780e", binding: %Vyasa.Adapters.Binding{__meta__: #Ecto.Schema.Metadata<:loaded, "bindings">, id: "001da594-3808-46cf-9b9c-5dfb3559780e", w_type: nil, field_key: ["target", "body_translit_meant"], node_id: nil, verse_id: nil, verse: #Ecto.Association.NotLoaded<association :verse is not loaded>, chapter_no: nil, chapter: #Ecto.Association.NotLoaded<association :chapter is not loaded>, source_id: nil, source: #Ecto.Association.NotLoaded<association :source is not loaded>, translation_id: "97a7a662-a91b-486f-93e8-7ae932d01a1a", translation: #Ecto.Association.NotLoaded<association :translation is not loaded>, sheaf_id: nil, sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>, window: nil}, inserted_at: ~U[2024-10-11 04:31:50Z], updated_at: ~U[2024-10-11 04:31:50Z]}, %Vyasa.Sangh.Mark{__meta__: #Ecto.Schema.Metadata<:loaded, "marks">, id: "273a093d-4f90-40a4-b19a-2f8f7825d201", body: "truncated utc datetime", order: 1, state: :live, verse_id: nil, sheaf_id: "7f4ab16b-0caf-4009-ba2a-3ddded81d9aa", sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>, binding_id: "ef39315b-530c-4841-ba32-86773f451727", binding: %Vyasa.Adapt (truncated)
[debug] MOUNT VyasaWeb.ModeLive.Mediator
  Parameters: %{"chap_no" => "1", "source_title" => "hanuman_chalisa"}
  Session: %{"_csrf_token" => "DJ-RIoXwEzHW82rbb21le_8k"}
[debug] QUERY OK source="sessions" db=3.5ms idle=1690.4ms
SELECT s0."id", s0."inserted_at", s0."updated_at" FROM "sessions" AS s0 WHERE (s0."id" = $1) ["164eb05d-221a-4939-b180-8394e1a5515f"]
↳

* Fix duplicate id issue on verse matrix

* Standardise use of @event_target, cleanups

When using @event_target, the intent is that phx-target values
will be passed around. This must be agnostic to the 2 main ways of
supplying that argument, as a HTML selector, or as a module name (or @myself).
Therefore, we should discourage ourselves from doing format-strings at
the point of the @event_target being supplied as an argument, meaning:

good, because agnostic:
phx-target={@event_target}

bad, because hardcoded:
phx-target={"#" <> @event_target}
* in this case, the event trigger will throw a dom error.

* [Attempt]: Sanitise, defrag orders in marks-list

If this is an anti-pattern, then this commit should be reverted.

* UI fixes: hide buttons on marks when !is_editable?

* Add in stub event handlers to prevent crashes

Temporary stuff, will be addressed in immediate-next PR

* Minor changes

* Toggle edit state for marks content

* Partial implementation of edit marks

the form stuff doesn't exist so it's not wired up yet. To be frank,
im' not sure how to set up a form without it needing to hold state.

* [BUGGY] Wire up form update for edit

this does the following:
1. wires up the form like how we usedd it in createMark
2. actually captures the event properly within the event handler,
everything looks good at that point, even the edit_mark_in_marks
function on inspection looks good
3. the marks is getting assigned to properly because the newly edited
mark content is seen after doing a dom refresh
4. HOWEVER, the print statement at the sheaf_update function DOES NOT
show the correct, updated marks in the sheaf

here's a dump for it for reference

[debug] HANDLE EVENT "editMarkContent" in VyasaWeb.ModeLive.Mediator
  Component: VyasaWeb.Context.Read
  Parameters: %{"mark_id" => "02218551-591f-4450-abbd-a7b7d76fd48e"}
[debug] Replied in 2ms
[debug] HANDLE EVENT "editMarkContent" in VyasaWeb.ModeLive.Mediator
  Component: VyasaWeb.Context.Read
  Parameters: %{"mark_body" => "  testing\n\n\nwhat hte heck", "mark_id" => "02218551-591f-4450-abbd-a7b7d76fd48e"}
>>> UPDATE SHEAF -- SHOULD BE WRITING TO DB NOW: %Vyasa.Sangh.Sheaf{
  __meta__: #Ecto.Schema.Metadata<:loaded, "sheafs">,
  id: "7f4ab16b-0caf-4009-ba2a-3ddded81d9aa",
  body: nil,
  active: true,
  path: %EctoLtree.LabelTree{labels: ["7f4ab16b"]},
  signature: nil,
  traits: ["draft"],
  child_count: 0,
  session_id: "164eb05d-221a-4939-b180-8394e1a5515f",
  session: #Ecto.Association.NotLoaded<association :session is not loaded>,
  parent_id: nil,
  parent: #Ecto.Association.NotLoaded<association :parent is not loaded>,
  marks: [
    %Vyasa.Sangh.Mark{
      __meta__: #Ecto.Schema.Metadata<:loaded, "marks">,
      id: "555eb625-e392-496e-9831-4f4c130be6fd",
      body: "wonderful stuff",
      order: 5,
      state: :live,
      verse_id: nil,
      sheaf_id: "7f4ab16b-0caf-4009-ba2a-3ddded81d9aa",
      sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>,
      binding_id: "072124d0-5e27-4601-832f-35eaa6426879",
      binding: %Vyasa.Adapters.Binding{
        __meta__: #Ecto.Schema.Metadata<:loaded, "bindings">,
        id: "072124d0-5e27-4601-832f-35eaa6426879",
        w_type: nil,
        field_key: ["target", "body_translit_meant"],
        node_id: nil,
        verse_id: nil,
        verse: #Ecto.Association.NotLoaded<association :verse is not loaded>,
        chapter_no: nil,
        chapter: #Ecto.Association.NotLoaded<association :chapter is not loaded>,
        source_id: nil,
        source: #Ecto.Association.NotLoaded<association :source is not loaded>,
        translation_id: "97a7a662-a91b-486f-93e8-7ae932d01a1a",
        translation: #Ecto.Association.NotLoaded<association :translation is not loaded>,
        sheaf_id: nil,
        sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>,
        window: nil
      },
      inserted_at: ~U[2024-10-12 08:46:54Z],
      updated_at: ~U[2024-10-12 08:46:54Z]
    },
    %Vyasa.Sangh.Mark{
      __meta__: #Ecto.Schema.Metadata<:loaded, "marks">,
      id: "b22a5661-8268-4875-be26-a12256414136",
      body: nil,
      order: 5,
      state: :draft,
      verse_id: nil,
      sheaf_id: "7f4ab16b-0caf-4009-ba2a-3ddded81d9aa",
      sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>,
      binding_id: "90e18044-73b2-4ede-a149-a381de893b9f",
      binding: %Vyasa.Adapters.Binding{
        __meta__: #Ecto.Schema.Metadata<:loaded, "bindings">,
        id: "90e18044-73b2-4ede-a149-a381de893b9f",
        w_type: nil,
        field_key: ["target", "body_translit_meant"],
        node_id: nil,
        verse_id: nil,
        verse: #Ecto.Association.NotLoaded<association :verse is not loaded>,
        chapter_no: nil,
        chapter: #Ecto.Association.NotLoaded<association :chapter is not loaded>,
        source_id: nil,
        source: #Ecto.Association.NotLoaded<association :source is not loaded>,
        translation_id: "fc80709a-39dc-4b9c-95c3-1d64ce818302",
        translation: #Ecto.Association.NotLoaded<association :translation is not loaded>,
        sheaf_id: nil,
        sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>,
        window: nil
      },
      inserted_at: ~U[2024-10-12 09:52:40Z],
      updated_at: ~U[2024-10-12 09:52:40Z]
    },
    %Vyasa.Sangh.Mark{
      __meta__: #Ecto.Schema.Metadata<:loaded, "marks">,
      id: "8af43833-575c-4eb8-83b1-eb4e58509e4c",
      body: nil,
      order: 4,
      state: :draft,
      verse_id: nil,
      sheaf_id: "7f4ab16b-0caf-4009-ba2a-3ddded81d9aa",
      sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>,
      binding_id: "23b70937-ed81-47fe-a560-ee14287bff7d",
      binding: %Vyasa.Adapters.Binding{
        __meta__: #Ecto.Schema.Metadata<:loaded, "bindings">,
        id: "23b70937-ed81-47fe-a560-ee14287bff7d",
        w_type: nil,
        field_key: ["target", "body_translit_meant"],
        node_id: nil,
        verse_id: nil,
        verse: #Ecto.Association.NotLoaded<association :verse is not loaded>,
        chapter_no: nil,
        chapter: #Ecto.Association.NotLoaded<association :chapter is not loaded>,
        source_id: nil,
        source: #Ecto.Association.NotLoaded<association :source is not loaded>,
        translation_id: "97a7a662-a91b-486f-93e8-7ae932d01a1a",
        translation: #Ecto.Association.NotLoaded<association :translation is not loaded>,
        sheaf_id: nil,
        sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>,
        window: nil
      },
      inserted_at: ~U[2024-10-12 09:46:13Z],
      updated_at: ~U[2024-10-12 09:46:13Z]
    },
    %Vyasa.Sangh.Mark{
      __meta__: #Ecto.Schema.Metadata<:loaded, "marks">,
      id: "c7ad47e6-629d-4382-936d-64d757772c4e",
      body: nil,
      order: 3,
      state: :draft,
      verse_id: nil,
      sheaf_id: "7f4ab16b-0caf-4009-ba2a-3ddded81d9aa",
      sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>,
      binding_id: "d5758230-7966-4f9b-8c16-ae13998cd71b",
      binding: %Vyasa.Adapters.Binding{
        __meta__: #Ecto.Schema.Metadata<:loaded, "bindings">,
        id: "d5758230-7966-4f9b-8c16-ae13998cd71b",
        w_type: nil,
        field_key: ["target", "body_translit_meant"],
        node_id: nil,
        verse_id: nil,
        verse: #Ecto.Association.NotLoaded<association :verse is not loaded>,
        chapter_no: nil,
        chapter: #Ecto.Association.NotLoaded<association :chapter is not loaded>,
        source_id: nil,
        source: #Ecto.Association.NotLoaded<association :source is not loaded>,
        translation_id: "fc80709a-39dc-4b9c-95c3-1d64ce818302",
        translation: #Ecto.Association.NotLoaded<association :translation is not loaded>,
        sheaf_id: nil,
        sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>,
        window: nil
      },
      inserted_at: ~U[2024-10-12 09:44:09Z],
      updated_at: ~U[2024-10-12 09:44:09Z]
    },
    %Vyasa.Sangh.Mark{
      __meta__: #Ecto.Schema.Metadata<:loaded, "marks">,
      id: "02218551-591f-4450-abbd-a7b7d76fd48e",
      body: "testing",
      order: 2,
      state: :live,
      verse_id: nil,
      sheaf_id: "7f4ab16b-0caf-4009-ba2a-3ddded81d9aa",
      sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>,
      binding_id: "19ffdc82-a5d8-49c3-8b01-1559736dad80",
      binding: %Vyasa.Adapters.Binding{
        __meta__: #Ecto.Schema.Metadata<:loaded, "bindings">,
        id: "19ffdc82-a5d8-49c3-8b01-1559736dad80",
        w_type: nil,
        field_key: ["target", "body_translit_meant"],
        node_id: nil,
        verse_id: nil,
        verse: #Ecto.Association.NotLoaded<association :verse is not loaded>,
        chapter_no: nil,
        chapter: #Ecto.Association.NotLoaded<association :chapter is not loaded>,
        source_id: nil,
        source: #Ecto.Association.NotLoaded<association :source is not loaded>,
        translation_id: "fc80709a-39dc-4b9c-95c3-1d64ce818302",
        translation: #Ecto.Association.NotLoaded<association :translation is not loaded>,
        sheaf_id: nil,
        sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>,
        window: nil
      },
      inserted_at: ~U[2024-10-12 09:43:19Z],
      updated_at: ~U[2024-10-12 09:43:19Z]
    },
    %Vyasa.Sangh.Mark{
      __meta__: #Ecto.Schema.Metadata<:loaded, "marks">,
      id: "90c6036a-9bd1-4b65-82d5-f121ec4d7867",
      body: nil,
      order: 2,
      state: :draft,
      verse_id: nil,
      sheaf_id: "7f4ab16b-0caf-4009-ba2a-3ddded81d9aa",
      sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>,
      binding_id: "b92f990d-99a2-4f04-a2d4-d1135021ee8c",
      binding: %Vyasa.Adapters.Binding{
        __meta__: #Ecto.Schema.Metadata<:loaded, "bindings">,
        id: "b92f990d-99a2-4f04-a2d4-d1135021ee8c",
        w_type: nil,
        field_key: ["target", "body_translit_meant"],
        node_id: nil,
        verse_id: nil,
        verse: #Ecto.Association.NotLoaded<association :verse is not loaded>,
        chapter_no: nil,
        chapter: #Ecto.Association.NotLoaded<association :chapter is not loaded>,
        source_id: nil,
        source: #Ecto.Association.NotLoaded<association :source is not loaded>,
        translation_id: "97a7a662-a91b-486f-93e8-7ae932d01a1a",
        translation: #Ecto.Association.NotLoaded<association :translation is not loaded>,
        sheaf_id: nil,
        sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>,
        window: nil
      },
      inserted_at: ~U[2024-10-11 09:03:00Z],
      updated_at: ~U[2024-10-11 09:03:00Z]
    }
  ],
  inserted_at: ~N[2024-09-27 00:51:48],
  updated_at: ~N[2024-09-27 00:51:48]
}
[debug] Replied in 81ms
[debug] HANDLE EVENT "verses::focus_toggle_on_quick_mark_drafting" in VyasaWeb.ModeLive.Mediator
  Component: VyasaWeb.Context.Read
  Parameters: %{"is_focusing?" => false, "value" => ""}
[debug] Replied in 129µs
iex([email protected])17>

* marks order force

* old man mark is not feeling so good

* ReWrite how marks get initialised @ :show_verse (#119)

* Minor change in fn signature

* Add init_draft_reflector()

* Don't rely on the time async message passing

* Use custom generic_modal_wrapper

This one has more specific callback attributes and tailwind classes can
be injected to it.

* Create data and ui skeletons for sheaf_creator

* Add support for human friendly time formatting

* Setup skeleton for replyto context

Some pending todo functions for how the reply to context shall be determined

* Standardise UI, improve wrapper's default UI

* Improve generic_modal_wrapper styling slots

* Wire sheaf creation form to stubbed event handler

Relevant TODOs have been added

* Use session.name for signature, add handler stubs

* Edit marks in read mode (#118)

* Add generic debug dump component

This makes life easy when wiring things up

* Rename namespace for Context.Read.*

* Groundwork: add discuss component w sheafs

* Init Context.Components mod for common components

* Add skeletons for Sheaf Container

Container managers sheaf state within itself.
Should actually make the verse-matrix use this container, sometime.

* Minor changes, add some TODOs to share

explicit todos

Minor change

* Add live component EditableMarkDisplay

* Add UI improvements to EditableMarkDisplay

The edit button on quick draft should only be seen when the dropdown is
expanded and all the marks can be seen. The general pattern I'm trying
to follow is that buttons should only be shown when an action makes
sense. So here, if the user can't even see the marks currently
accumulating, then the user shouldn't have the chance to edit any marks.

Notice that the EditableMarkDisplay is a live_component that is a child
of a function component (collapsible_marks_display). This is so that it can keep its own state and
do it's own event-handling. I'm not sure if this is pattern-breaking.
A reference to the actual parent live_component that calls collapsible_marks_display
will always be there in case there's a need for the parent to handle
any particular events. So comms b/w live_components is still going to be
via phx-target values.

* Change <input/> -> <textarea/> fr quick_draft_form

* Add tailwind config for custom svg icons

not sure how the scaling for this works, seems like i can't just put in
the class="h-5 w-5" to do the scaling

* Let custom svg be scalable

* Subtly shift the ping indicator to control panel

* Marks ordering in Sheaf and L-Trees  (#114)

* do sheafs grow on trees

* sangh session dealing with lineage

* Solve initial order problem

* fix: ensure non-null id used @ EditableMarkDisplay

---------

Co-authored-by: ks0m1c_dharma <[email protected]>

* Trigger Diff

* TOMBSTONING

* Fix bugs and revert ui for read_mode:delete marks

1.  JIT generate id for marks yet to be inserted to the db: instead of
    using a temp id, I'm actually assigning a JIT-generated id for a
    mark even if that isn't inserted into the db yet. this has two
    benefits: div ids have meaningful static ids (e.g.
    mark-container-\<\> mark.id) regardless of whether that mark has
    been inserted into the db or not. While doing this, the changeset
    for marks has been udpated to add id as well. This fixes a bunch of
    id-based errors as well.

2.  while doing 1, it came to light that the bindHoverune handlers were
    not handling the draft mark update properly (i.e. not using the
    already existing update function in mark) . it's changed now,
    example of the diff:

    ``` diff
      @impl true
      def handle_event(
            "bindHoveRune",
            %{"binding" => bind = %{"verse_id" => verse_id}},
            %{
              assigns: %{
                kv_verses: verses,
                marks: [%Mark{state: :draft, verse_id: curr_verse_id} = d_mark | marks]
              }
            } = socket
          )
          when is_binary(curr_verse_id) and verse_id != curr_verse_id do
        # binding here blocks the stream from appending to quote
        bind = Draft.bind_node(bind)

        bound_verses =
          verses
           |> then(&put_in(&1[verse_id].binding, bind))
           |> then(&put_in(&1[curr_verse_id].binding, nil))

    +    updated_draft_mark = d_mark |> Mark.update_mark(%{binding: bind, verse_id: verse_id})
    +
         {:noreply,
          socket
          |> mutate_verses(curr_verse_id, bound_verses)
          |> mutate_verses(verse_id, bound_verses)
    -     |> assign(:marks, [%{d_mark | binding: bind, verse_id: verse_id} | marks])}
    +     |> assign(:marks, [updated_draft_mark | marks])}
       end
    ```

3.  add ui state structs: all of the relevant ui states have structs
    that are intended to be static interfaces. this felt better than
    directly keeping state within various sockets and is done with a
    view to remove live components and change them to function
    components wherever possible.

4.  bugfix for `order()`:

    - it had an off-by-one-error
    - shifted it to Vyasa.Sangh.Mark
    - also note that the order shall be 1-indexed instead of 0-indexed
      for human-friendliness

5.  minor fixes:

    1.  fix update<sub>mark</sub> default argument

        ``` diff
        -def update_mark(%Mark{} = draft_mark, opts \\ []) do
        +def update_mark(%Mark{} = draft_mark, opts \\ %{}) do
        ```

1.  In this commit, the marks<sub>ui</sub> is NOT kept by the read
    context module, that's why when I update things by create mark or
    delete mark, the ui state is not preserved and initial, default
    state is seen. This was intentionally done in this commit because
    I'm having problems with duplicate ids for verses for some reason,
    I'll show it in the next commit, so that the problem can be clearly
    seen.

* [BUGGY] keep marks_ui within ReadContext

This is buggy, not sure why there's a duplicate yet.  will come back to
it after lunch

Replication Steps:
1. delete all marks and see there's no error
2. create first mark ==> no error
3. create second mark ==> crashes due to duplicate verse id

Crash dump:

[debug] Replied in 13ms
[error] GenServer #PID<0.8416.0> terminating
** (RuntimeError) found duplicate ID "verse-7d9d588a-34fc-4f19-b974-fc32b49b6a61" for component VyasaWeb.Context.Read.VerseMatrix when rendering template
    (phoenix_live_view 1.0.0-rc.6) lib/phoenix_live_view/diff.ex:634: anonymous fn/5 in Phoenix.LiveView.Diff.render_pending_components/6
    (elixir 1.17.2) lib/enum.ex:2531: Enum."-reduce/3-lists^foldl/2-0-"/3
    (phoenix_live_view 1.0.0-rc.6) lib/phoenix_live_view/diff.ex:631: anonymous fn/4 in Phoenix.LiveView.Diff.render_pending_components/6
    (stdlib 5.2.3) maps.erl:416: :maps.fold_1/4
    (phoenix_live_view 1.0.0-rc.6) lib/phoenix_live_view/diff.ex:625: Phoenix.LiveView.Diff.render_pending_components/6
    (phoenix_live_view 1.0.0-rc.6) lib/phoenix_live_view/diff.ex:217: Phoenix.LiveView.Diff.write_component/4
    (phoenix_live_view 1.0.0-rc.6) lib/phoenix_live_view/channel.ex:662: Phoenix.LiveView.Channel.component_handle/4
    (stdlib 5.2.3) gen_server.erl:1095: :gen_server.try_handle_info/3
    (stdlib 5.2.3) gen_server.erl:1183: :gen_server.handle_msg/6
    (stdlib 5.2.3) proc_lib.erl:251: :proc_lib.wake_up/3
Last message: %Phoenix.Socket.Message{topic: "lv:phx-F_1MH_6F0ciqVqwi", event: "event", payload: %{"cid" => 3, "event" => "createMark", "type" => "form", "value" => "body=how+about+now%2C+any+duplicate%3F"}, ref: "23", join_ref: "4"}
State: %{socket: #Phoenix.LiveView.Socket<id: "phx-F_1MH_6F0ciqVqwi", endpoint: VyasaWeb.Endpoint, view: VyasaWeb.ModeLive.Mediator, parent_pid: nil, root_pid: #PID<0.8416.0>, router: VyasaWeb.Router, assigns: %{mode: %VyasaWeb.ModeLive.UserMode{mode: "read", default_ui_state: %VyasaWeb.ModeLive.UiState{show_media_bridge?: true, show_action_bar?: true}, mode_icon_name: "hero-book-open", quick_actions: [:mark_quote, :bookmark], control_panel_modes: ["discuss"], mode_actions: [:mark_quote, :bookmark], action_bar_actions: [:nav_back, :nav_fwd], action_bar_info_types: nil, action_bar_component: VyasaWeb.MediaLive.MediaBridge, action_bar_component_selector: "media-bridge", control_panel_component: VyasaWeb.ControlPanel, control_panel_component_selector: "control-panel", mode_context_component: VyasaWeb.Context.Read, mode_context_component_selector: "read"}, session: %VyasaWeb.Session{name: "ritesh kumar", id: "IhrQV0ypqg8bHakbvb2bymNF", active: true, sangh: %Vyasa.Sangh.Session{__meta__: #Ecto.Schema.Metadata<:loaded, "sessions">, id: "164eb05d-221a-4939-b180-8394e1a5515f", sheafs: #Ecto.Association.NotLoaded<association :sheafs is not loaded>, inserted_at: ~U[2024-09-27 00:51:48Z], updated_at: ~U[2024-09-27 00:51:48Z]}, last_opened: "2024-09-23T11:03:32.022987Z"}, __changed__: %{}, flash: %{}, locale: "en-GB", url_params: %{"chap_no" => "1", "source_title" => "hanuman_chalisa"}, live_action: :show_verses, ui_state: %VyasaWeb.ModeLive.UiState{show_media_bridge?: true, show_action_bar?: true}, device_type: :desktop, tz: %{timezone: "Asia/Singapore", timezone_offset: 480}}, transport_pid: #PID<0.8403.0>, ...>, components: {%{15 => {VyasaWeb.Context.Read.VerseMatrix, "verse-aa3ad88b-0de1-443e-b471-c08a44e67c61", %{id: "verse-aa3ad88b-0de1-443e-b471-c08a44e67c61", edge: [%{title: "1.10", field: [:body], verseup: {:big, "dn"}}, %{node: %Vyasa.Written.Translation{__meta__: #Ecto.Schema.Metadata<:loaded, "translations">, id: "651676b6-ffc3-41c1-b525-f376989f639e", lang: "en", type: "verses", target: %Vyasa.Written.Translation.Target{id: "dd20a94f-8f34-49f8-8da8-4321cfecf172", title: nil, title_translit: nil, body: "प्रभु चरित्र सुनिबे को रसिया ।\n\nराम लखन सीता मन बसिया ॥८॥", body_meant: nil, body_translit: "prabhu caritra sunibe ko rasiyā .\n\nrāma lakhana sītā mana basiyā ..8..", body_translit_meant: "You feel extremely delighted in listening to Lord Rama’s doings and conduct. Lord Rama, Mother Sita, and Lord Laxmana dwell forever in your heart."}, verse_id: "aa3ad88b-0de1-443e-b471-c08a44e67c61", verse: #Ecto.Association.NotLoaded<association :verse is not loaded>, chapter_no: nil, chapter: #Ecto.Association.NotLoaded<association :chapter is not loaded>, source_id: "63918acd-77a9-451a-b8d1-8d5b73208eae", source: #Ecto.Association.NotLoaded<association :source is not loaded>}, field: [:target, :body_translit], verseup: :mid}, %{node: %Vyasa.Written.Translation{__meta__: #Ecto.Schema.Metadata<:loaded, "translations">, id: "651676b6-ffc3-41c1-b525-f376989f639e", lang: "en", type: "verses", target: %Vyasa.Written.Translation.Target{id: "dd20a94f-8f34-49f8-8da8-4321cfecf172", title: nil, title_translit: nil, body: "प्रभु चरित्र सुनिबे को रसिया ।\n\nराम लखन सीता मन बसिया ॥८॥", body_meant: nil, body_translit: "prabhu caritra sunibe ko rasiyā .\n\nrāma lakhana sītā mana basiyā ..8..", body_translit_meant: "You feel extremely delighted in listening to Lord Rama’s doings and conduct. Lord Rama, Mother Sita, and Lord Laxmana dwell forever in your heart."}, verse_id: "aa3ad88b-0de1-443e-b471-c08a44e67c61", verse: #Ecto.Association.NotLoaded<association :verse is not loaded>, chapter_no: nil, chapter: #Ecto.Association.NotLoaded<association :chapter is not loaded>, source_id: "63918acd-77a9-451a-b8d1-8d5b73208eae", source: #Ecto.Association.NotLoaded<association :source is not loaded>}, field: [:target, :body_translit_meant], verseup: :mid}, %{node: %Vyasa.Written.Translation{__meta__: #Ecto.Schema.Metadata<:loaded, "translations">, id: "651676b6-ffc3-41c1-b525-f376989f639e", lang: "en", type: "verses", target: %Vyasa.Written.Translation.Target{id: "dd20a94f-8f34-49f8-8da8-4321cfecf172", title: nil, title_translit: nil, body: "प्रभु चरित्र सुनिबे को रसिया ।\n\nराम लखन सीता मन बसिया ॥८॥", body_meant: nil, body_translit: "prabhu caritra sunibe ko rasiyā .\n\nrāma lakhana sītā mana basiyā ..8..", body_translit_meant: "You feel extremely delighted in listening to Lord Rama’s doings and conduct. Lord Rama, Mother Sita, and Lord Laxmana dwell forever in your heart."}, verse_id: "aa3ad88b-0de1-443e-b471-c08a44e67c61", verse: #Ecto.Association.NotLoaded<association :verse is not loaded>, chapter_no: nil, chapter: #Ecto.Association.NotLoaded<association :chapter is not loaded>, source_id: "63918acd-77a9-451a-b8d1-8d5b73208eae", source: #Ecto.Association.NotLoaded<association :source is not loaded>}, field: [:target, :body], verseup: :mid}], __changed__: %{}, flash: %{}, marks: [%Vyasa.Sangh.Mark{__meta__: #Ecto.Schema.Metadata<:loaded, "marks">, id: "5dfdb167-6c57-46dd-a0c4-10b52cb03a85", body: "wonderful", order: 2, state: :live, verse_id: nil, sheaf_id: "7f4ab16b-0caf-4009-ba2a-3ddded81d9aa", sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>, binding_id: "001da594-3808-46cf-9b9c-5dfb3559780e", binding: %Vyasa.Adapters.Binding{__meta__: #Ecto.Schema.Metadata<:loaded, "bindings">, id: "001da594-3808-46cf-9b9c-5dfb3559780e", w_type: nil, field_key: ["target", "body_translit_meant"], node_id: nil, verse_id: nil, verse: #Ecto.Association.NotLoaded<association :verse is not loaded>, chapter_no: nil, chapter: #Ecto.Association.NotLoaded<association :chapter is not loaded>, source_id: nil, source: #Ecto.Association.NotLoaded<association :source is not loaded>, translation_id: "97a7a662-a91b-486f-93e8-7ae932d01a1a", translation: #Ecto.Association.NotLoaded<association :translation is not loaded>, sheaf_id: nil, sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>, window: nil}, inserted_at: ~U[2024-10-11 04:31:50Z], updated_at: ~U[2024-10-11 04:31:50Z]}, %Vyasa.Sangh.Mark{__meta__: #Ecto.Schema.Metadata<:loaded, "marks">, id: "273a093d-4f90-40a4-b19a-2f8f7825d201", body: "truncated utc datetime", order: 1, state: :live, verse_id: nil, sheaf_id: "7f4ab16b-0caf-4009-ba2a-3ddded81d9aa", sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>, binding_id: "ef39315b-530c-4841-ba32-86773f451727", binding: %Vyasa.Adapt (truncated)
[debug] MOUNT VyasaWeb.ModeLive.Mediator
  Parameters: %{"chap_no" => "1", "source_title" => "hanuman_chalisa"}
  Session: %{"_csrf_token" => "DJ-RIoXwEzHW82rbb21le_8k"}
[debug] QUERY OK source="sessions" db=3.5ms idle=1690.4ms
SELECT s0."id", s0."inserted_at", s0."updated_at" FROM "sessions" AS s0 WHERE (s0."id" = $1) ["164eb05d-221a-4939-b180-8394e1a5515f"]
↳

* Fix duplicate id issue on verse matrix

* Standardise use of @event_target, cleanups

When using @event_target, the intent is that phx-target values
will be passed around. This must be agnostic to the 2 main ways of
supplying that argument, as a HTML selector, or as a module name (or @myself).
Therefore, we should discourage ourselves from doing format-strings at
the point of the @event_target being supplied as an argument, meaning:

good, because agnostic:
phx-target={@event_target}

bad, because hardcoded:
phx-target={"#" <> @event_target}
* in this case, the event trigger will throw a dom error.

* [Attempt]: Sanitise, defrag orders in marks-list

If this is an anti-pattern, then this commit should be reverted.

* UI fixes: hide buttons on marks when !is_editable?

* Add in stub event handlers to prevent crashes

Temporary stuff, will be addressed in immediate-next PR

* Minor changes

* Toggle edit state for marks content

* Partial implementation of edit marks

the form stuff doesn't exist so it's not wired up yet. To be frank,
im' not sure how to set up a form without it needing to hold state.

* [BUGGY] Wire up form update for edit

this does the following:
1. wires up the form like how we usedd it in createMark
2. actually captures the event properly within the event handler,
everything looks good at that point, even the edit_mark_in_marks
function on inspection looks good
3. the marks is getting assigned to properly because the newly edited
mark content is seen after doing a dom refresh
4. HOWEVER, the print statement at the sheaf_update function DOES NOT
show the correct, updated marks in the sheaf

here's a dump for it for reference

[debug] HANDLE EVENT "editMarkContent" in VyasaWeb.ModeLive.Mediator
  Component: VyasaWeb.Context.Read
  Parameters: %{"mark_id" => "02218551-591f-4450-abbd-a7b7d76fd48e"}
[debug] Replied in 2ms
[debug] HANDLE EVENT "editMarkContent" in VyasaWeb.ModeLive.Mediator
  Component: VyasaWeb.Context.Read
  Parameters: %{"mark_body" => "  testing\n\n\nwhat hte heck", "mark_id" => "02218551-591f-4450-abbd-a7b7d76fd48e"}
>>> UPDATE SHEAF -- SHOULD BE WRITING TO DB NOW: %Vyasa.Sangh.Sheaf{
  __meta__: #Ecto.Schema.Metadata<:loaded, "sheafs">,
  id: "7f4ab16b-0caf-4009-ba2a-3ddded81d9aa",
  body: nil,
  active: true,
  path: %EctoLtree.LabelTree{labels: ["7f4ab16b"]},
  signature: nil,
  traits: ["draft"],
  child_count: 0,
  session_id: "164eb05d-221a-4939-b180-8394e1a5515f",
  session: #Ecto.Association.NotLoaded<association :session is not loaded>,
  parent_id: nil,
  parent: #Ecto.Association.NotLoaded<association :parent is not loaded>,
  marks: [
    %Vyasa.Sangh.Mark{
      __meta__: #Ecto.Schema.Metadata<:loaded, "marks">,
      id: "555eb625-e392-496e-9831-4f4c130be6fd",
      body: "wonderful stuff",
      order: 5,
      state: :live,
      verse_id: nil,
      sheaf_id: "7f4ab16b-0caf-4009-ba2a-3ddded81d9aa",
      sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>,
      binding_id: "072124d0-5e27-4601-832f-35eaa6426879",
      binding: %Vyasa.Adapters.Binding{
        __meta__: #Ecto.Schema.Metadata<:loaded, "bindings">,
        id: "072124d0-5e27-4601-832f-35eaa6426879",
        w_type: nil,
        field_key: ["target", "body_translit_meant"],
        node_id: nil,
        verse_id: nil,
        verse: #Ecto.Association.NotLoaded<association :verse is not loaded>,
        chapter_no: nil,
        chapter: #Ecto.Association.NotLoaded<association :chapter is not loaded>,
        source_id: nil,
        source: #Ecto.Association.NotLoaded<association :source is not loaded>,
        translation_id: "97a7a662-a91b-486f-93e8-7ae932d01a1a",
        translation: #Ecto.Association.NotLoaded<association :translation is not loaded>,
        sheaf_id: nil,
        sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>,
        window: nil
      },
      inserted_at: ~U[2024-10-12 08:46:54Z],
      updated_at: ~U[2024-10-12 08:46:54Z]
    },
    %Vyasa.Sangh.Mark{
      __meta__: #Ecto.Schema.Metadata<:loaded, "marks">,
      id: "b22a5661-8268-4875-be26-a12256414136",
      body: nil,
      order: 5,
      state: :draft,
      verse_id: nil,
      sheaf_id: "7f4ab16b-0caf-4009-ba2a-3ddded81d9aa",
      sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>,
      binding_id: "90e18044-73b2-4ede-a149-a381de893b9f",
      binding: %Vyasa.Adapters.Binding{
        __meta__: #Ecto.Schema.Metadata<:loaded, "bindings">,
        id: "90e18044-73b2-4ede-a149-a381de893b9f",
        w_type: nil,
        field_key: ["target", "body_translit_meant"],
        node_id: nil,
        verse_id: nil,
        verse: #Ecto.Association.NotLoaded<association :verse is not loaded>,
        chapter_no: nil,
        chapter: #Ecto.Association.NotLoaded<association :chapter is not loaded>,
        source_id: nil,
        source: #Ecto.Association.NotLoaded<association :source is not loaded>,
        translation_id: "fc80709a-39dc-4b9c-95c3-1d64ce818302",
        translation: #Ecto.Association.NotLoaded<association :translation is not loaded>,
        sheaf_id: nil,
        sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>,
        window: nil
      },
      inserted_at: ~U[2024-10-12 09:52:40Z],
      updated_at: ~U[2024-10-12 09:52:40Z]
    },
    %Vyasa.Sangh.Mark{
      __meta__: #Ecto.Schema.Metadata<:loaded, "marks">,
      id: "8af43833-575c-4eb8-83b1-eb4e58509e4c",
      body: nil,
      order: 4,
      state: :draft,
      verse_id: nil,
      sheaf_id: "7f4ab16b-0caf-4009-ba2a-3ddded81d9aa",
      sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>,
      binding_id: "23b70937-ed81-47fe-a560-ee14287bff7d",
      binding: %Vyasa.Adapters.Binding{
        __meta__: #Ecto.Schema.Metadata<:loaded, "bindings">,
        id: "23b70937-ed81-47fe-a560-ee14287bff7d",
        w_type: nil,
        field_key: ["target", "body_translit_meant"],
        node_id: nil,
        verse_id: nil,
        verse: #Ecto.Association.NotLoaded<association :verse is not loaded>,
        chapter_no: nil,
        chapter: #Ecto.Association.NotLoaded<association :chapter is not loaded>,
        source_id: nil,
        source: #Ecto.Association.NotLoaded<association :source is not loaded>,
        translation_id: "97a7a662-a91b-486f-93e8-7ae932d01a1a",
        translation: #Ecto.Association.NotLoaded<association :translation is not loaded>,
        sheaf_id: nil,
        sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>,
        window: nil
      },
      inserted_at: ~U[2024-10-12 09:46:13Z],
      updated_at: ~U[2024-10-12 09:46:13Z]
    },
    %Vyasa.Sangh.Mark{
      __meta__: #Ecto.Schema.Metadata<:loaded, "marks">,
      id: "c7ad47e6-629d-4382-936d-64d757772c4e",
      body: nil,
      order: 3,
      state: :draft,
      verse_id: nil,
      sheaf_id: "7f4ab16b-0caf-4009-ba2a-3ddded81d9aa",
      sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>,
      binding_id: "d5758230-7966-4f9b-8c16-ae13998cd71b",
      binding: %Vyasa.Adapters.Binding{
        __meta__: #Ecto.Schema.Metadata<:loaded, "bindings">,
        id: "d5758230-7966-4f9b-8c16-ae13998cd71b",
        w_type: nil,
        field_key: ["target", "body_translit_meant"],
        node_id: nil,
        verse_id: nil,
        verse: #Ecto.Association.NotLoaded<association :verse is not loaded>,
        chapter_no: nil,
        chapter: #Ecto.Association.NotLoaded<association :chapter is not loaded>,
        source_id: nil,
        source: #Ecto.Association.NotLoaded<association :source is not loaded>,
        translation_id: "fc80709a-39dc-4b9c-95c3-1d64ce818302",
        translation: #Ecto.Association.NotLoaded<association :translation is not loaded>,
        sheaf_id: nil,
        sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>,
        window: nil
      },
      inserted_at: ~U[2024-10-12 09:44:09Z],
      updated_at: ~U[2024-10-12 09:44:09Z]
    },
    %Vyasa.Sangh.Mark{
      __meta__: #Ecto.Schema.Metadata<:loaded, "marks">,
      id: "02218551-591f-4450-abbd-a7b7d76fd48e",
      body: "testing",
      order: 2,
      state: :live,
      verse_id: nil,
      sheaf_id: "7f4ab16b-0caf-4009-ba2a-3ddded81d9aa",
      sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>,
      binding_id: "19ffdc82-a5d8-49c3-8b01-1559736dad80",
      binding: %Vyasa.Adapters.Binding{
        __meta__: #Ecto.Schema.Metadata<:loaded, "bindings">,
        id: "19ffdc82-a5d8-49c3-8b01-1559736dad80",
        w_type: nil,
        field_key: ["target", "body_translit_meant"],
        node_id: nil,
        verse_id: nil,
        verse: #Ecto.Association.NotLoaded<association :verse is not loaded>,
        chapter_no: nil,
        chapter: #Ecto.Association.NotLoaded<association :chapter is not loaded>,
        source_id: nil,
        source: #Ecto.Association.NotLoaded<association :source is not loaded>,
        translation_id: "fc80709a-39dc-4b9c-95c3-1d64ce818302",
        translation: #Ecto.Association.NotLoaded<association :translation is not loaded>,
        sheaf_id: nil,
        sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>,
        window: nil
      },
      inserted_at: ~U[2024-10-12 09:43:19Z],
      updated_at: ~U[2024-10-12 09:43:19Z]
    },
    %Vyasa.Sangh.Mark{
      __meta__: #Ecto.Schema.Metadata<:loaded, "marks">,
      id: "90c6036a-9bd1-4b65-82d5-f121ec4d7867",
      body: nil,
      order: 2,
      state: :draft,
      verse_id: nil,
      sheaf_id: "7f4ab16b-0caf-4009-ba2a-3ddded81d9aa",
      sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>,
      binding_id: "b92f990d-99a2-4f04-a2d4-d1135021ee8c",
      binding: %Vyasa.Adapters.Binding{
        __meta__: #Ecto.Schema.Metadata<:loaded, "bindings">,
        id: "b92f990d-99a2-4f04-a2d4-d1135021ee8c",
        w_type: nil,
        field_key: ["target", "body_translit_meant"],
        node_id: nil,
        verse_id: nil,
        verse: #Ecto.Association.NotLoaded<association :verse is not loaded>,
        chapter_no: nil,
        chapter: #Ecto.Association.NotLoaded<association :chapter is not loaded>,
        source_id: nil,
        source: #Ecto.Association.NotLoaded<association :source is not loaded>,
        translation_id: "97a7a662-a91b-486f-93e8-7ae932d01a1a",
        translation: #Ecto.Association.NotLoaded<association :translation is not loaded>,
        sheaf_id: nil,
        sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>,
        window: nil
      },
      inserted_at: ~U[2024-10-11 09:03:00Z],
      updated_at: ~U[2024-10-11 09:03:00Z]
    }
  ],
  inserted_at: ~N[2024-09-27 00:51:48],
  updated_at: ~N[2024-09-27 00:51:48]
}
[debug] Replied in 81ms
[debug] HANDLE EVENT "verses::focus_toggle_on_quick_mark_drafting" in VyasaWeb.ModeLive.Mediator
  Component: VyasaWeb.Context.Read
  Parameters: %{"is_focusing?" => false, "value" => ""}
[debug] Replied in 129µs
iex([email protected])17>

* marks order force

* old man mark is not feeling so good

* ReWrite how marks get initialised @ :show_verse (#119)

* Minor change in fn signature

* Add init_draft_reflector()

---------

Co-authored-by: ks0m1c_dharma <[email protected]>

* Minor changes

* Add a generic modal wrapper (#120)

* Add generic debug dump component

This makes life easy when wiring things up

* Rename namespace for Context.Read.*

* Groundwork: add discuss component w sheafs

* Init Context.Components mod for common components

* Add skeletons for Sheaf Container

Container managers sheaf state within itself.
Should actually make the verse-matrix use this container, sometime.

* Minor changes, add some TODOs to share

explicit todos

Minor change

* Add live component EditableMarkDisplay

* Add UI improvements to EditableMarkDisplay

The edit button on quick draft should only be seen when the dropdown is
expanded and all the marks can be seen. The general pattern I'm trying
to follow is that buttons should only be shown when an action makes
sense. So here, if the user can't even see the marks currently
accumulating, then the user shouldn't have the chance to edit any marks.

Notice that the EditableMarkDisplay is a live_component that is a child
of a function component (collapsible_marks_display). This is so that it can keep its own state and
do it's own event-handling. I'm not sure if this is pattern-breaking.
A reference to the actual parent live_component that calls collapsible_marks_display
will always be there in case there's a need for the parent to handle
any particular events. So comms b/w live_components is still going to be
via phx-target values.

* Change <input/> -> <textarea/> fr quick_draft_form

* Add tailwind config for custom svg icons

not sure how the scaling for this works, seems like i can't just put in
the class="h-5 w-5" to do the scaling

* Let custom svg be scalable

* Subtly shift the ping indicator to control panel

* Marks ordering in Sheaf and L-Trees  (#114)

* do sheafs grow on trees

* sangh session dealing with lineage

* Solve initial order problem

* fix: ensure non-null id used @ EditableMarkDisplay

---------

Co-authored-by: ks0m1c_dharma <[email protected]>

* Trigger Diff

* TOMBSTONING

* Fix bugs and revert ui for read_mode:delete marks

1.  JIT generate id for marks yet to be inserted to the db: instead of
    using a temp id, I'm actually assigning a JIT-generated id for a
    mark even if that isn't inserted into the db yet. this has two
    benefits: div ids have meaningful static ids (e.g.
    mark-container-\<\> mark.id) regardless of whether that mark has
    been inserted into the db or not. While doing this, the changeset
    for marks has been udpated to add id as well. This fixes a bunch of
    id-based errors as well.

2.  while doing 1, it came to light that the bindHoverune handlers were
    not handling the draft mark update properly (i.e. not using the
    already existing update function in mark) . it's changed now,
    example of the diff:

    ``` diff
      @impl true
      def handle_event(
            "bindHoveRune",
            %{"binding" => bind = %{"verse_id" => verse_id}},
            %{
              assigns: %{
                kv_verses: verses,
                marks: [%Mark{state: :draft, verse_id: curr_verse_id} = d_mark | marks]
              }
            } = socket
          )
          when is_binary(curr_verse_id) and verse_id != curr_verse_id do
        # binding here blocks the stream from appending to quote
        bind = Draft.bind_node(bind)

        bound_verses =
          verses
           |> then(&put_in(&1[verse_id].binding, bind))
           |> then(&put_in(&1[curr_verse_id].binding, nil))

    +    updated_draft_mark = d_mark |> Mark.update_mark(%{binding: bind, verse_id: verse_id})
    +
         {:noreply,
          socket
          |> mutate_verses(curr_verse_id, bound_verses)
          |> mutate_verses(verse_id, bound_verses)
    -     |> assign(:marks, [%{d_mark | binding: bind, verse_id: verse_id} | marks])}
    +     |> assign(:marks, [updated_draft_mark | marks])}
       end
    ```

3.  add ui state structs: all of the relevant ui states have structs
    that are intended to be static interfaces. this felt better than
    directly keeping state within various sockets and is done with a
    view to remove live components and change them to function
    components wherever possible.

4.  bugfix for `order()`:

    - it had an off-by-one-error
    - shifted it to Vyasa.Sangh.Mark
    - also note that the order shall be 1-indexed instead of 0-indexed
      for human-friendliness

5.  minor fixes:

    1.  fix update<sub>mark</sub> default argument

        ``` diff
        -def update_mark(%Mark{} = draft_mark, opts \\ []) do
        +def update_mark(%Mark{} = draft_mark, opts \\ %{}) do
        ```

1.  In this commit, the marks<sub>ui</sub> is NOT kept by the read
    context module, that's why when I update things by create mark or
    delete mark, the ui state is not preserved and initial, default
    state is seen. This was intentionally done in this commit because
    I'm having problems with duplicate ids for verses for some reason,
    I'll show it in the next commit, so that the problem can be clearly
    seen.

* [BUGGY] keep marks_ui within ReadContext

This is buggy, not sure why there's a duplicate yet.  will come back to
it after lunch

Replication Steps:
1. delete all marks and see there's no error
2. create first mark ==> no error
3. create second mark ==> crashes due to duplicate verse id

Crash dump:

[debug] Replied in 13ms
[error] GenServer #PID<0.8416.0> terminating
** (RuntimeError) found duplicate ID "verse-7d9d588a-34fc-4f19-b974-fc32b49b6a61" for component VyasaWeb.Context.Read.VerseMatrix when rendering template
    (phoenix_live_view 1.0.0-rc.6) lib/phoenix_live_view/diff.ex:634: anonymous fn/5 in Phoenix.LiveView.Diff.render_pending_components/6
    (elixir 1.17.2) lib/enum.ex:2531: Enum."-reduce/3-lists^foldl/2-0-"/3
    (phoenix_live_view 1.0.0-rc.6) lib/phoenix_live_view/diff.ex:631: anonymous fn/4 in Phoenix.LiveView.Diff.render_pending_components/6
    (stdlib 5.2.3) maps.erl:416: :maps.fold_1/4
    (phoenix_live_view 1.0.0-rc.6) lib/phoenix_live_view/diff.ex:625: Phoenix.LiveView.Diff.render_pending_components/6
    (phoenix_live_view 1.0.0-rc.6) lib/phoenix_live_view/diff.ex:217: Phoenix.LiveView.Diff.write_component/4
    (phoenix_live_view 1.0.0-rc.6) lib/phoenix_live_view/channel.ex:662: Phoenix.LiveView.Channel.component_handle/4
    (stdlib 5.2.3) gen_server.erl:1095: :gen_server.try_handle_info/3
    (stdlib 5.2.3) gen_server.erl:1183: :gen_server.handle_msg/6
    (stdlib 5.2.3) proc_lib.erl:251: :proc_lib.wake_up/3
Last message: %Phoenix.Socket.Message{topic: "lv:phx-F_1MH_6F0ciqVqwi", event: "event", payload: %{"cid" => 3, "event" => "createMark", "type" => "form", "value" => "body=how+about+now%2C+any+duplicate%3F"}, ref: "23", join_ref: "4"}
State: %{socket: #Phoenix.LiveView.Socket<id: "phx-F_1MH_6F0ciqVqwi", endpoint: VyasaWeb.Endpoint, view: VyasaWeb.ModeLive.Mediator, parent_pid: nil, root_pid: #PID<0.8416.0>, router: VyasaWeb.Router, assigns: %{mode: %VyasaWeb.ModeLive.UserMode{mode: "read", default_ui_state: %VyasaWeb.ModeLive.UiState{show_media_bridge?: true, show_action_bar?: true}, mode_icon_name: "hero-book-open", quick_actions: [:mark_quote, :bookmark], control_panel_modes: ["discuss"], mode_actions: [:mark_quote, :bookmark], action_bar_actions: [:nav_back, :nav_fwd], action_bar_info_types: nil, action_bar_component: VyasaWeb.MediaLive.MediaBridge, action_bar_component_selector: "media-bridge", control_panel_component: VyasaWeb.ControlPanel, control_panel_component_selector: "control-panel", mode_context_component: VyasaWeb.Context.Read, mode_context_component_selector: "read"}, session: %VyasaWeb.Session{name: "ritesh kumar", id: "IhrQV0ypqg8bHakbvb2bymNF", active: true, sangh: %Vyasa.Sangh.Session{__meta__: #Ecto.Schema.Metadata<:loaded, "sessions">, id: "164eb05d-221a-4939-b180-8394e1a5515f", sheafs: #Ecto.Association.NotLoaded<association :sheafs is not loaded>, inserted_at: ~U[2024-09-27 00:51:48Z], updated_at: ~U[2024-09-27 00:51:48Z]}, last_opened: "2024-09-23T11:03:32.022987Z"}, __changed__: %{}, flash: %{}, locale: "en-GB", url_params: %{"chap_no" => "1", "source_title" => "hanuman_chalisa"}, live_action: :show_verses, ui_state: %VyasaWeb.ModeLive.UiState{show_media_bridge?: true, show_action_bar?: true}, device_type: :desktop, tz: %{timezone: "Asia/Singapore", timezone_offset: 480}}, transport_pid: #PID<0.8403.0>, ...>, components: {%{15 => {VyasaWeb.Context.Read.VerseMatrix, "verse-aa3ad88b-0de1-443e-b471-c08a44e67c61", %{id: "verse-aa3ad88b-0de1-443e-b471-c08a44e67c61", edge: [%{title: "1.10", field: [:body], verseup: {:big, "dn"}}, %{node: %Vyasa.Written.Translation{__meta__: #Ecto.Schema.Metadata<:loaded, "translations">, id: "651676b6-ffc3-41c1-b525-f376989f639e", lang: "en", type: "verses", target: %Vyasa.Written.Translation.Target{id: "dd20a94f-8f34-49f8-8da8-4321cfecf172", title: nil, title_translit: nil, body: "प्रभु चरित्र सुनिबे को रसिया ।\n\nराम लखन सीता मन बसिया ॥८॥", body_meant: nil, body_translit: "prabhu caritra sunibe ko rasiyā .\n\nrāma lakhana sītā mana basiyā ..8..", body_translit_meant: "You feel extremely delighted in listening to Lord Rama’s doings and conduct. Lord Rama, Mother Sita, and Lord Laxmana dwell forever in your heart."}, verse_id: "aa3ad88b-0de1-443e-b471-c08a44e67c61", verse: #Ecto.Association.NotLoaded<association :verse is not loaded>, chapter_no: nil, chapter: #Ecto.Association.NotLoaded<association :chapter is not loaded>, source_id: "63918acd-77a9-451a-b8d1-8d5b73208eae", source: #Ecto.Association.NotLoaded<association :source is not loaded>}, field: [:target, :body_translit], verseup: :mid}, %{node: %Vyasa.Written.Translation{__meta__: #Ecto.Schema.Metadata<:loaded, "translations">, id: "651676b6-ffc3-41c1-b525-f376989f639e", lang: "en", type: "verses", target: %Vyasa.Written.Translation.Target{id: "dd20a94f-8f34-49f8-8da8-4321cfecf172", title: nil, title_translit: nil, body: "प्रभु चरित्र सुनिबे को रसिया ।\n\nराम लखन सीता मन बसिया ॥८॥", body_meant: nil, body_translit: "prabhu caritra sunibe ko rasiyā .\n\nrāma lakhana sītā mana basiyā ..8..", body_translit_meant: "You feel extremely delighted in listening to Lord Rama’s doings and conduct. Lord Rama, Mother Sita, and Lord Laxmana dwell forever in your heart."}, verse_id: "aa3ad88b-0de1-443e-b471-c08a44e67c61", verse: #Ecto.Association.NotLoaded<association :verse is not loaded>, chapter_no: nil, chapter: #Ecto.Association.NotLoaded<association :chapter is not loaded>, source_id: "63918acd-77a9-451a-b8d1-8d5b73208eae", source: #Ecto.Association.NotLoaded<association :source is not loaded>}, field: [:target, :body_translit_meant], verseup: :mid}, %{node: %Vyasa.Written.Translation{__meta__: #Ecto.Schema.Metadata<:loaded, "translations">, id: "651676b6-ffc3-41c1-b525-f376989f639e", lang: "en", type: "verses", target: %Vyasa.Written.Translation.Target{id: "dd20a94f-8f34-49f8-8da8-4321cfecf172", title: nil, title_translit: nil, body: "प्रभु चरित्र सुनिबे को रसिया ।\n\nराम लखन सीता मन बसिया ॥८॥", body_meant: nil, body_translit: "prabhu caritra sunibe ko rasiyā .\n\nrāma lakhana sītā mana basiyā ..8..", body_translit_meant: "You feel extremely delighted in listening to Lord Rama’s doings and conduct. Lord Rama, Mother Sita, and Lord Laxmana dwell forever in your heart."}, verse_id: "aa3ad88b-0de1-443e-b471-c08a44e67c61", verse: #Ecto.Association.NotLoaded<association :verse is not loaded>, chapter_no: nil, chapter: #Ecto.Association.NotLoaded<association :chapter is not loaded>, source_id: "63918acd-77a9-451a-b8d1-8d5b73208eae", source: #Ecto.Association.NotLoaded<association :source is not loaded>}, field: [:target, :body], verseup: :mid}], __changed__: %{}, flash: %{}, marks: [%Vyasa.Sangh.Mark{__meta__: #Ecto.Schema.Metadata<:loaded, "marks">, id: "5dfdb167-6c57-46dd-a0c4-10b52cb03a85", body: "wonderful", order: 2, state: :live, verse_id: nil, sheaf_id: "7f4ab16b-0caf-4009-ba2a-3ddded81d9aa", sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>, binding_id: "001da594-3808-46cf-9b9c-5dfb3559780e", binding: %Vyasa.Adapters.Binding{__meta__: #Ecto.Schema.Metadata<:loaded, "bindings">, id: "001da594-3808-46cf-9b9c-5dfb3559780e", w_type: nil, field_key: ["target", "body_translit_meant"], node_id: nil, verse_id: nil, verse: #Ecto.Association.NotLoaded<association :verse is not loaded>, chapter_no: nil, chapter: #Ecto.Association.NotLoaded<association :chapter is not loaded>, source_id: nil, source: #Ecto.Association.NotLoaded<association :source is not loaded>, translation_id: "97a7a662-a91b-486f-93e8-7ae932d01a1a", translation: #Ecto.Association.NotLoaded<association :translation is not loaded>, sheaf_id: nil, sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>, window: nil}, inserted_at: ~U[2024-10-11 04:31:50Z], updated_at: ~U[2024-10-11 04:31:50Z]}, %Vyasa.Sangh.Mark{__meta__: #Ecto.Schema.Metadata<:loaded, "marks">, id: "273a093d-4f90-40a4-b19a-2f8f7825d201", body: "truncated utc datetime", order: 1, state: :live, verse_id: nil, sheaf_id: "7f4ab16b-0caf-4009-ba2a-3ddded81d9aa", sheaf: #Ecto.Association.NotLoaded<association :sheaf is not loaded>, binding_id: "ef39315b-530c-4841-ba32-86773f451727", binding: %Vyasa.Adapt (truncated)
[debug] MOUNT VyasaWeb.ModeLive.Mediator
  Parameters: %{"chap_no" => "1", "source_title" => "hanuman_chalisa"}
  Session: %{"_csrf_token" => "DJ-RIoXwEzHW82rbb21le_8k"}
[debug] QUERY OK source="sessions" db=3.5ms idle=1690.4ms
SELECT s0."id", s0."inserted_at", s0."updated_at" FROM "sessions" AS s0 WHERE (s0."id" = $1) ["164eb05d-221a-4939-b180-8394e1a5515f"]
↳

* Fix duplicate id issue on verse matrix

* Standardise use of @event_target, cleanups

When using @event_target, the intent is that phx-target values
will be passed around. This must be agnostic to the 2 main ways of
supplying that argument, as a HTML selector, or as a module name (or @myself).
Therefore, we should discourage ourselves from doing format-strings at
the point of the @event_target being supplied as an argument, meaning:

good, because agnostic:
phx-target={@event_target}

bad, because hardcoded:
phx-target={"#" <> @event_target}
* in this case, the event trigger will throw a dom er…
@rtshkmr rtshkmr changed the title Discussions Epic 💬 Discussions Epic 💬 Oct 26, 2024
ks0m1c and others added 4 commits October 27, 2024 15:05
* HoverBraces

* css madness as expected

* certified icon wrangler

* the forgotten icon lolol

* specify top-3 for closing quote icon

---------

Co-authored-by: ks0m1c_dharma <[email protected]>
Co-authored-by: Ritesh Kumar <[email protected]>
* force diffs

* Simplify read::init_reply_to_context

* Add init routines for draft & replyto

1 Init Drafting and Reply To Contexts
═════════════════════════════════════

  now that we have the read context cleaned up for both data and ui
  being managed at the sheaf-level, we just have to do the same for
  discuss, interfaced via the lattice.

1.1 Notes
─────────

  1. At the same time we need to provision contexts:

     ‣ Reply to context: what is the current intent that you’re replying
       to
     ‣ drafting context: what are we currently drafting marks for?
     the lattices shall be the source of truth: -> sheaf_lattice: for
     data on sheafs, including marks -> sheaf_ui_lattice: for data on ui
     states

     We shall keep the lattices as the source of truth, so the
     `reply_to' and `draft_reflector' will be keeping the state, and the
     variables in state will just be the paths that point to the state,
     or in this case, the labels.

     Since state will be within the lattices, we don’t need a
     `draft_reflector_ui_id'

  2. There’s actually a bit of duplicated patterns in both read and
     discuss modes, but I shall continue with the duplication until the
     patterns are well defined and ready to be refactored. I think the
     way to know if it’s time to refactor something is if the
     refactoring is going to be an easy task.
* share binding

* binding jump

* supress field for user selected bindings

* focus bindings and cleanup

---------

Co-authored-by: ks0m1c_dharma <[email protected]>
* suneye

* faviconagraphy

* sharing primitives to sessionbox more universal

* Foundations of Disciple Panels

* Resolve Refs to Anonymised User IDs

* WorksPID assigned for future Binding

Acked-by: ks0m1c_dharma <[email protected]>

* Moduledocs & PR Cleanup

---------

Co-authored-by: ks0m1c_dharma <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants