Skip to content
Open
Show file tree
Hide file tree
Changes from 29 commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
1832659
Trigger minor diff
rtshkmr Oct 9, 2024
e264c33
Delete marks from read mode (#117)
rtshkmr Oct 12, 2024
d21f545
[BUGFIX] Explicitly pipe apply_action, not helm
Oct 14, 2024
258f4d3
Edit marks in read mode (#118)
rtshkmr Oct 17, 2024
6b16b92
Add a generic modal wrapper (#120)
rtshkmr Oct 17, 2024
007e0a3
Sheaf CRUD: Add UI skeleton, data plumbing for creating sheafs (#121)
rtshkmr Oct 26, 2024
a8c1921
Add helpers to generate a family of sheafs for testing disc mode (#122)
rtshkmr Oct 26, 2024
7f8f07d
Add data, ui lattices and ui primitives for the discuss context (#124)
rtshkmr Oct 26, 2024
858ae27
Refactor: read mode keeps sheaf state only (#125)
rtshkmr Oct 26, 2024
400ad53
Read mode: reply_to relies on draft sheaf's parent (#127)
rtshkmr Oct 26, 2024
cf8e00a
force diffs
rtshkmr Oct 26, 2024
2a3d465
Simplify read::init_reply_to_context
rtshkmr Oct 26, 2024
9c39948
Add init routines for draft & replyto
rtshkmr Oct 26, 2024
75f0c8d
Add ui stubs for sheaf engagement buttons
rtshkmr Oct 26, 2024
965a26e
Cleanup the attrs accepted by curr components
rtshkmr Oct 26, 2024
cabb226
Inject children into sheaf summary
rtshkmr Oct 26, 2024
9da9eb6
the holy brace (#130)
ks0m1c Oct 27, 2024
5b6d315
Discuss: init drafting and reply_to contexts (#128)
rtshkmr Oct 27, 2024
5f7d5e9
Merge branch 'epic/discussions' into feat/context-gate/discuss-ui-sta…
rtshkmr Oct 27, 2024
7dced6d
Handle toggling of collapsible_sheaf_container
rtshkmr Oct 27, 2024
a1bb2b8
Pass sheaf(_ui) as props instead of marks(_ui)
rtshkmr Oct 27, 2024
1b4577d
Support ui::toggle_marks_display_collapsibility
rtshkmr Oct 27, 2024
97e2c8d
marks: ui:toggle, and editing in published sheafs
rtshkmr Oct 28, 2024
0061b47
Modal toggle for quick reply
rtshkmr Oct 28, 2024
063b5ba
Add focus pin toggle
rtshkmr Oct 29, 2024
5ab1b36
Add example for navigate::visit_mark
rtshkmr Oct 29, 2024
453314b
vanity: Add reddit-sheaftop collapse toggle
rtshkmr Oct 29, 2024
c812a6c
Add sheaf::share_sheaf icon and empty handler
rtshkmr Oct 29, 2024
6d74e7a
Cleanup to improve the review process
rtshkmr Oct 30, 2024
afabc77
bind, share and jump around (#132)
ks0m1c Nov 11, 2024
1a68e46
Merge branch 'epic/discussions' into feat/context-gate/discuss-ui-sta…
rtshkmr Nov 14, 2024
9f9aa6c
Styling changes to highlighted span
rtshkmr Nov 14, 2024
c98aaa2
Add mode-specific routes, inject mode @ mediator (#133)
rtshkmr Nov 15, 2024
487b0c9
Fix parsing error when extracting injected mode (#134)
rtshkmr Nov 16, 2024
937eb68
Disciple Panels (#137)
ks0m1c Dec 8, 2024
3079b5b
yMerge branch 'epic/discussions' into feat/context-gate/discuss-ui-st…
Dec 8, 2024
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
1 change: 0 additions & 1 deletion README.org
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ Wherever there be anything you dost not comprehend, cease to continue writing
-- Vyasa, Adi Parva - Mahabharatam
#+END_QUOTE


* What is the _*Vyasa Project*_?
=TODO=

Expand Down
19 changes: 7 additions & 12 deletions assets/js/hooks/hoverune.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,14 +35,6 @@ function floatHoveRune({ clientX, clientY }) {
top: `${y}px`,
});
});

// computePosition(virtualEl, hoverune, {placement: 'top-end', middleware: [inline(getSelectRect.x, getSelectRect.y), offset(5)]}).then(({x, y}) => {
// hoverune.classList.remove("hidden")
// Object.assign(hoverune.style, {
// left: `${getSelectRect.x}px`,
// top: `${y}px`,
// });
// })
}

const findHook = (el) => findParent(el, "phx-hook", "HoveRune");
Expand Down Expand Up @@ -70,16 +62,19 @@ export default HoveRune = {
return;
}

var getSelectRect = selection.getRangeAt(0).getBoundingClientRect();
var range = selection.getRangeAt(0);
var getSelectRect = range.getBoundingClientRect();
const getSelectText = selection.toString();
//const validElem = findHook(target)
// const isMarginote = findMarginote(target)
const isNode = findNode(target);

console.log("binding selected here!")
console.log(selection)

if (isNode) {
binding = forgeBinding(target, [
"node",
"node_id",
"text",
"field",
"verse_id",
]);
Expand All @@ -90,7 +85,7 @@ export default HoveRune = {
target: `#${this.eventTarget}`,
payload: { binding: binding },
});
this.pushEventTo(`#${this.eventTarget}`, "bindHoveRune", {
this.pushEventTo(`#${this.eventTarget}`, "hoverune::bindHoveRune", {
binding: binding,
});

Expand Down
4 changes: 4 additions & 0 deletions assets/js/hooks/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ import HoveRune from "./hoverune.js";
import Scrolling from "./scrolling.js";
import ButtonClickRelayer from "./button_click_relayer.js";
import SessionBox from "./session_box.js";
import TextareaAutoResize from "./textarea_auto_resize.js";
import PseudoForm from "./pseudo_form.js";

let Hooks = {
ShareQuoteButton,
Expand All @@ -26,6 +28,8 @@ let Hooks = {
Scrolling,
ButtonClickRelayer,
SessionBox,
TextareaAutoResize,
PseudoForm,
};

export default Hooks;
103 changes: 103 additions & 0 deletions assets/js/hooks/pseudo_form.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
/**
* {PseudoForm}
*
* This hook facilitates the capture of input values from "form elements" without resorting to
* tradition form-submission mechanisms. This approach is useful to avoid the nested form problem -- wherein
* nested forms lead to unintended behaviour because a submission event in a child form will get bubbled out (propagated)
* to the parent, as per HTML-DOM spec and will cause the parent's submit to also be triggerred. This would mean that
* without the user desiring it so, there will be a form submission. While there are ways to hack this, for example by
* preventing the bubble propagation from happening, those solutions are not long-term, which brings us to
* consider this hook as an alternative approach. By using this hook, we can effectively manage input values while keeping
* components stateless and avoiding the complexities associated with nested forms.

* **Why Nested Forms Are an Antipattern**: [perplexity-generated section]
* - **Event Propagation Issues**: Nested forms can cause submit events to bubble up, leading to unintended submissions of parent forms.
* - **Complexity**: Managing state and events across nested forms increases the complexity of your application, making it harder to maintain.
* - **Accessibility Concerns**: Screen readers and assistive technologies may struggle with nested forms, potentially leading to a poor user experience.
* - **HTML Specification**: The HTML specification does not support nested forms, which can lead to inconsistent behavior across different browsers.
*
* **Value of Stateless Function Components**: [perplexity-generated section]
* - Using function components that do not rely on form state allows for greater composability and flexibility.
* - It enables nesting of components without the constraints imposed by traditional form handling, allowing for cleaner and more maintainable code.
* - This approach promotes reusability and modularity within your codebase, making it easier to build complex UIs without the overhead of managing form state.
*
* Overall Mechanism for this hook:
* - The hook listens for a specified event on the element it is attached to.
* - When the event is triggered, it captures the value of a designated input element.
* - It then pushes an event to the LiveView server with the captured input value and any additional payload.
*
* Expected Dataset Parameters:
* - `data-event-to-capture`: A string representing the type of event to listen for (e.g., "click").
* This allows flexibility in determining which user interaction will trigger the value capture.
*
* - `data-target-selector`: A CSS selector string that identifies the input element from which to capture
* the value. This makes the hook generic and reusable for different types of inputs (e.g., textareas,
* text inputs).
*
* - `data-event-name`: A string representing the name of the event to be pushed to the LiveView server.
* If not provided, it defaults to "submitPseudoForm".
*
* - `data-event-target`: A string representing the target for the event push. This should match the
* target LiveView or component that will handle the event on the server side.
*
* - `data-event-payload`: A JSON string representing any additional data you want to send along with
* the captured input value. This allows for more complex interactions without needing to modify
* component state externally. This is actually a static part of the eventual payload that the event needs to have, we shall merge this with the input that we will be reading.
*
* Example Usage:
* <button
* phx-hook="PseudoForm"
* data-event-to-capture="click"
* data-target-selector="#input-id"
* data-event-name="mark::editMarkContent"
* data-event-target="targetLiveView"
* data-event-payload='{"additional_key": "additional_value"}'
* >
* Submit
* </button>
*
* NOTE: this currently only handles single-input fields. This hook may be extended to
* handle a group of input fields following a similar approach; otherwise, we should fallback to
* typical LiveView idioms that deal with how to handle forms.
*/

PseudoForm = {
mounted() {
const eventToCapture = this.el.getAttribute("data-event-to-capture");
this.el.addEventListener(eventToCapture, (_event) => {
const targetSelector = this.el.getAttribute("data-target-selector");
const eventName =
this.el.getAttribute("data-event-name") || "submitPseudoForm";
const eventPayload = JSON.parse(
this.el.getAttribute("data-event-payload") || "{}",
);
const eventTarget = this.el.getAttribute("data-event-target");
const inputElement = document.querySelector(targetSelector);

if (inputElement) {
const value = inputElement.value; // Reads the current value of the input
const finalPayload = {
...eventPayload,
input: value.trim(),
};
console.info("Using a pseudoform", {
eventName,
eventTarget,
eventPayload,
value,
finalPayload,
});
this.pushEventTo(eventTarget, eventName, finalPayload);
} else {
console.warn("Desired input element not found, params:", {
targetSelector,
eventName,
eventTarget,
eventPayload,
});
}
});
},
};

export default PseudoForm;
14 changes: 14 additions & 0 deletions assets/js/hooks/textarea_auto_resize.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
/**
* This hook, if injected to a textarea, will automatically resize the
* textarea height (bound by max height, if already defined).
* */

export default TextareaAutoResize = {
mounted() {
this.handleInput();
},
handleInput() {
this.el.style.height = "auto"; // Resets height to auto to shrink if needed
this.el.style.height = `${this.el.scrollHeight}px`; // Sets height based on scrollHeight
},
};
50 changes: 48 additions & 2 deletions assets/tailwind.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,28 @@ module.exports = {
theme: {
extend: {
animation: {
ripple: "ripple 0.6s linear",
ripple: "ripple 1s cubic-bezier(0.4, 0, 0.2, 1) infinite",
pulseBorder: "pulseBorder 1.5s ease-in-out infinite",
},
keyframes: {
ripple: {
"0%": { transform: "scale(0)", opacity: "0.5" },
"0%": { transform: "scale(0)", opacity: "1" },
"100%": { transform: "scale(4)", opacity: "0" },
},
pulseBorder: {
"0%": {
borderColor: "transparent",
transform: "scale(1)",
},
"50%": {
borderColor: "var(--color-brand)", // Use your defined brand color
transform: "scale(1.05)", // Slightly scale up
},
"100%": {
borderColor: "transparent",
transform: "scale(1)",
},
},
},
fontFamily: {
dn: ['"Karm"', "sans-serif"],
Expand Down Expand Up @@ -122,5 +137,36 @@ module.exports = {
{ values },
);
}),
// Embeds Custom SVG Icons (https://heroicons.com) into your app.css bundle
plugin(function ({ matchComponents, theme }) {
let iconsDir = path.join(__dirname, "./vendor/customicons");
let values = {};
fs.readdirSync(iconsDir).forEach((file) => {
let name = path.basename(file, ".svg");
values[name] = { name, fullPath: path.join(iconsDir, file) };
});
matchComponents(
{
custom: ({ name, fullPath }) => {
let content = fs
.readFileSync(fullPath)
.toString()
.replace(/\r?\n|\r/g, "");
return {
[`--custom-${name}`]: `url('data:image/svg+xml;utf8,${content}')`,
"-webkit-mask": `var(--custom-${name})`,
mask: `var(--custom-${name})`,
"mask-repeat": "no-repeat",
"background-color": "currentColor",
"vertical-align": "middle",
display: "inline-block",
width: theme("spacing.5"),
height: theme("spacing.5"),
};
},
},
{ values },
);
}),
],
};
8 changes: 8 additions & 0 deletions assets/vendor/customicons/README.org
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
* Custom SVG Icons
This follows a similar patterns as how the default hero-icons are vendored-in.

We shall keep all assets as lean as possible, so vendoring svgs when we need is better than adding a whole new icon pack.
This aims to reduce the build-time and keep bundle-sizes small.

** Useful Resources
1) [[https://icon-sets.iconify.design][iconify icon sets]] - open source, contains a wide variety of icon packs
4 changes: 4 additions & 0 deletions assets/vendor/customicons/icon-formkit-reply.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions assets/vendor/customicons/icon-ion-navigate.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 6 additions & 0 deletions assets/vendor/customicons/icon-mingcute-edit-4-line.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 6 additions & 0 deletions assets/vendor/customicons/icon-mingcute-save-line.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions assets/vendor/customicons/icon-park-outline-quote-start.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions assets/vendor/customicons/icon-ph-share-fat-light.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 6 additions & 0 deletions assets/vendor/customicons/icon-ph-sign-out-duotone.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions assets/vendor/customicons/icon-recent-changes-ltr.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions assets/vendor/customicons/icon-sort-down.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions assets/vendor/customicons/icon-sort-up.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
23 changes: 23 additions & 0 deletions assets/vendor/customicons/spinner-bars-scale-middle.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading