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

Binds to Sheaf #139

Open
wants to merge 4 commits into
base: feat/discussion/ui-iteration-improve-sheaf-display
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 40 additions & 16 deletions assets/js/hooks/hoverune.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,14 +37,39 @@ function floatHoveRune({ clientX, clientY }) {
});
}

const findMatchingSpan = ({ node_id, field }) => {
// Early return if missing either criteria
if (!node_id || !field) return null;

// Find first span with both exact matches
return document.querySelector(
`span[node_id="${node_id}"][field="${field}"]`
);
const findMatchingEl = (targetEl = document, {
node_id = null,
field = null
} = {}) => {
// If no identifier criteria provided, return all child elements
if (!node_id && !field) {
return Array.from(targetEl.children);
}

const elementTypes = ['span', 'div']
// Build dynamic selector based on provided criteria
const selectors = elementTypes.map(type => {
const conditions = [];

if (node_id) {
conditions.push(`[node_id="${node_id}"]`);
}

if (field) {
conditions.push(`[field="${field}"]`);
}

return `${type}${conditions.join('')}`;
});

// Try each selector in order
for (const selector of selectors) {
const matchedElement = targetEl.querySelector(selector);
if (matchedElement) return matchedElement;
}

// Return null if no match found
return null;
};

const findHook = (el) => findParent(el, "phx-hook", "HoveRune");
Expand All @@ -66,18 +91,17 @@ export default HoveRune = {
});

this.handleEvent("bind::jump", (bind) => {
console.warn(bind)
targetNode = findMatchingSpan(bind)
targetNode = findMatchingEl(this.el, bind)
if (targetNode) {
targetNode.focus();
targetNode.scrollIntoView({
behavior: "smooth",
block: "center",
});
targetNode.focus();
targetNode.scrollIntoView({
behavior: "smooth",
block: "center",
});
}

});
const targetEvents = ["pointerdown", "pointerup"];
const targetEvents = ["pointerdown", "pointerup"];
targetEvents.forEach((e) =>
window.addEventListener(e, ({ target }) => {
var selection = window.getSelection();
Expand Down
6 changes: 6 additions & 0 deletions lib/vyasa/draft.ex
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@ defmodule Vyasa.Draft do

end

def bind_node(node) do
bind_node(node, %Binding{})
end

# Uses the "field" attribute in the bind_target
# When the binding target is defined by a "field" attribute, it sets the field_key for the %Binding{} struct struct.
def bind_node(%{"field" => field} = node = _bind_target_payload, bind) do
Expand Down Expand Up @@ -64,6 +68,8 @@ defmodule Vyasa.Draft do

def get_binding!(id), do: Repo.get!(Binding, id) |> nodify() |> fieldify()

defp nodify(%Binding{sheaf_id: id} = b) when not is_nil(id), do: %{b | node_id: id}

defp nodify(%Binding{translation_id: id} = b) when not is_nil(id), do: %{b | node_id: id}

defp nodify(%Binding{verse_id: id} = b) when not is_nil(id), do: %{b | node_id: id}
Expand Down
16 changes: 16 additions & 0 deletions lib/vyasa/sangh/sheaf_lattice.ex
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,22 @@ defmodule Vyasa.Sangh.SheafLattice do
end
end

def recurse_sheaf_is_expanded?(ui_lattice, lattice_key) do
lattice_key
|> hist_reduce(ui_lattice, fn elem, lat -> toggle_sheaf_is_expanded?(lat, elem) end)
end

def hist_reduce(list, initial, fun) when is_list(list) do
list
|> Enum.reduce({initial, []}, fn elem, {acc, history} ->
new_history = [elem | history] |> Enum.reverse()
new_acc = fun.(new_history, acc)
{new_acc, new_history}
end)
|> elem(0)
end


@doc """
Reads sheaf layers from a lattice based on the specified level and match criteria.

Expand Down
8 changes: 5 additions & 3 deletions lib/vyasa_web/components/contexts/components.ex
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,7 @@ defmodule VyasaWeb.Context.Components do
type="button"
phx-click="navigate::visit_mark"
phx-value-mark_id={@mark.id}
phx-value-bind={@mark.binding_id}
phx-target={@marks_target}
class="flex items-center text-gray-600 hover:text-gray-800 flex-grow"
aria-label="Visit"
Expand Down Expand Up @@ -357,7 +358,7 @@ defmodule VyasaWeb.Context.Components do

def sheaf_display(assigns) do
~H"""
<div class={"border-l-2 border-gray-250 rounded-lg transition-all duration-200
<div node={Vyasa.Sangh.Sheaf} node_id={@sheaf.id} class={"border-l-2 border-gray-250 rounded-lg transition-all duration-200
#{if @sheaf_ui.is_focused? || @is_reply_to, do: "bg-brandExtraLight shadow-lg", else: "shadow-sm"}"}>
<.sheaf_summary
id={"sheaf-summary-" <> @id}
Expand Down Expand Up @@ -821,11 +822,12 @@ defmodule VyasaWeb.Context.Components do
</div>
<!-- Share Button -->
<.action_toggle_button
on_click="sheaf::share_sheaf"
on_click="bind::share"
true_text="Share"
icon_class="h-4 w-4 mr-1"
true_icon_name="custom-icon-ph-share-fat-light"
phx-target="#content-display"
phx-value-node_id={@sheaf.id}
phx-value-node={Vyasa.Sangh.Sheaf}
phx-value-sheaf_path_labels={Jason.encode!(@sheaf |> Sheaf.get_path_labels() || [])}
button_class="font-light flex items-center text-gray-600 hover:text-gray-800 ml-2"
/>
Expand Down
48 changes: 15 additions & 33 deletions lib/vyasa_web/components/contexts/discuss.ex
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ defmodule VyasaWeb.Context.Discuss do
alias VyasaWeb.ModeLive.{UserMode}
alias VyasaWeb.Session
alias Phoenix.LiveView.Socket
alias Vyasa.Sangh.Session, as: SanghSession
alias Vyasa.Sangh
alias Vyasa.Sangh.{SheafLattice, Sheaf, Mark}
alias VyasaWeb.Context.Components.UiState.Sheaf, as: SheafUiState
Expand Down Expand Up @@ -42,12 +41,22 @@ defmodule VyasaWeb.Context.Discuss do
}
end


def update(%{id: "discuss", binding: %{sheaf_id: sheaf_id} = bind}, %{assigns: %{sheaf_ui_lattice: lat, draft_reflector_path: path}} =socket) do
%{path: %Ltree{labels: lat_key}} = Sangh.get_sheaf(sheaf_id)
{:ok,socket
|> assign(sheaf_ui_lattice: SheafLattice.recurse_sheaf_is_expanded?(lat, lat_key))
|> assign(draft_reflector_path: path)
|> push_event("bind::jump", bind)}
end


defp apply_action(
%Socket{
assigns: %{
session:
%Session{
sangh: %SanghSession{id: sangh_id} = _sangh_session
sangh: %Sangh.Session{id: sangh_id} = _sangh_session
} = _session
}
} = socket,
Expand All @@ -62,7 +71,6 @@ defmodule VyasaWeb.Context.Discuss do
|> init_drafting_context()
|> init_reply_to_context()
end

# when there is no sangh session in state:
defp apply_action(
%Socket{
Expand Down Expand Up @@ -684,34 +692,6 @@ defmodule VyasaWeb.Context.Discuss do
|> assign(reply_to_path: nil)}
end

@impl true
# TODO @ks0m1c another place that would require binding / permalinking apis
# equivalent handler for the read mode as well...
def handle_event(
"sheaf::share_sheaf",
%{
"sheaf_path_labels" => sheaf_labels
} = _params,
%Socket{
assigns: %{
session: %{sangh: %{id: _sangh_id}},
sheaf_lattice: %{} = sheaf_lattice,
sheaf_ui_lattice: %{} = _sheaf_ui_lattice
}
} = socket
)
when is_binary(sheaf_labels) do
lattice_key = Jason.decode!(sheaf_labels)
shareable_sheaf = sheaf_lattice |> SheafLattice.get_sheaf_from_lattice(lattice_key)

IO.inspect(shareable_sheaf, label: "TODO: sheaf::share_sheaf")

{
:noreply,
socket
}
end

def handle_event(
"sheaf::publish",
%{
Expand Down Expand Up @@ -781,7 +761,8 @@ defmodule VyasaWeb.Context.Discuss do
def handle_event(
"navigate::visit_mark",
%{
"mark_id" => mark_id
"mark_id" => mark_id,
"bind" => binding_id
} = _params,
%Socket{
assigns: %{
Expand All @@ -794,9 +775,10 @@ defmodule VyasaWeb.Context.Discuss do
when is_binary(mark_id) do
# Handle the event here (e.g., log it, update state, etc.)
IO.inspect(mark_id,
label: "navigate::visit_mark -- TODO"
label: "navigate::visit_mark" <> binding_id
)

# jump to mark behaviour binding ingestion
{:noreply, socket}
end

Expand Down
2 changes: 1 addition & 1 deletion lib/vyasa_web/components/contexts/read/verse_matrix.ex
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ defmodule VyasaWeb.Context.Read.VerseMatrix do
><.icon
name="custom-icon-park-outline-quote-start"
class="absolute -top-3.5 -left-5 cursor-ew-resize select-none text-red-600 opacity-80 z-20"
/><span class="bg-blue"><%= String.byte_slice(
/><span><%= String.byte_slice(
@content,
@window.start_quote,
@window.end_quote - @window.start_quote
Expand Down
1 change: 0 additions & 1 deletion lib/vyasa_web/components/contexts/read/verses.ex
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@ defmodule VyasaWeb.Context.Read.Verses do
<div
id="verses"
phx-update="stream"
phx-hook="HoveRune"
data-event-target={@user_mode.mode_context_component_selector}
>
<.live_component
Expand Down
40 changes: 40 additions & 0 deletions lib/vyasa_web/live/mode_live/mediator.ex
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,24 @@ defmodule VyasaWeb.ModeLive.Mediator do
|> UiState.assign(:focused_binding, bind)
end

defp maybe_focus_binding(
%{
assigns: %{
url_params: %{"node" => _, "node_id" => _} = params,
mode: %UserMode{
mode_context_component: component,
mode_context_component_selector: selector
}
}
} = socket
) do
{:ok, bind} = params |> Map.take(["node", "node_id"]) |> Draft.bind_node()
send_update(component, id: selector, binding: bind)

socket
|> UiState.assign(:focused_binding, bind)
end

defp maybe_focus_binding(socket) do
socket
end
Expand Down Expand Up @@ -271,6 +289,28 @@ defmodule VyasaWeb.ModeLive.Mediator do
{:noreply, socket |> UiState.assign(:focused_binding, bind)}
end


def handle_event(
"bind::share",
%{"node" => node, "node_id" => node_id} = _bind,
%Socket{
assigns: %{
url_params: %{path: path}
}
} = socket
) do

#bind node on return
# {:ok, shared_bind} =
# bind
# |> Draft.bind_node()
# |> Draft.create_binding()

{:noreply, socket
|> push_event("session::share", %{url: unverified_url(socket,"#{path}", [node: node, node_id: node_id])})
|> put_flash(:info, "binded to your clipboard")}
end

def handle_event(
"bind::share",
_,
Expand Down
2 changes: 1 addition & 1 deletion lib/vyasa_web/live/mode_live/mediator.html.heex
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@
</div>
</div>

<main id="main-content" class="flex-grow bg-primaryBackground px-4 py-8 sm:px-6 lg:px-8">
<main id="main-content" phx-hook="HoveRune" class="flex-grow bg-primaryBackground px-4 py-8 sm:px-6 lg:px-8">
<div class="fixed top-4 right-4 flex flex-col items-center space-y-2">
<.live_component id="assembly" session={@session} sangh={@sangh} class="cursor-pointer transition-opacity duration-300 z-10" module={VyasaWeb.AssemblyPresence} />
<div id="control-panel-container">
Expand Down