|
9 | 9 | const app = get_app_context(); |
10 | 10 | const page_browser = get_page_browser(); |
11 | 11 |
|
12 | | - let { path }: { path: DocumentPath } = $props(); |
| 12 | + let { path }: { path?: DocumentPath } = $props(); |
13 | 13 |
|
14 | 14 | let edit_link_command = $derived(svedit.session.commands?.edit_link); |
| 15 | + let toggle_link_command = $derived(svedit.session.commands?.toggle_link); |
| 16 | + let is_creating = $derived(toggle_link_command?.show_prompt === true); |
| 17 | + let is_open = $derived( |
| 18 | + edit_link_command?.show_prompt === true || toggle_link_command?.show_prompt === true |
| 19 | + ); |
| 20 | + let anchor_name = $derived(path ? `--${serialize_path(path)}` : '--selection-highlight'); |
15 | 21 | let target_node = $derived(get_target_node()); |
| 22 | + let is_new_link = $derived(is_creating || !target_node?.href); |
16 | 23 |
|
17 | 24 | function get_target_node() { |
18 | 25 | const selected_node = svedit.session.selected_node; |
|
29 | 36 | let dialog_ref = $state<HTMLDialogElement>(); |
30 | 37 |
|
31 | 38 | function save() { |
32 | | - if (target_node && 'href' in target_node) { |
| 39 | + if (is_creating) { |
| 40 | + if (href_input_value) { |
| 41 | + svedit.session.apply( |
| 42 | + svedit.session.tr.toggle_mark('link', { |
| 43 | + href: href_input_value, |
| 44 | + target: open_in_new_tab ? '_blank' : '_self' |
| 45 | + }) |
| 46 | + ); |
| 47 | + } |
| 48 | + } else if (target_node && 'href' in target_node) { |
33 | 49 | const tr = svedit.session.tr; |
34 | 50 | tr.set([target_node.id, 'href'], href_input_value); |
35 | 51 | tr.set([target_node.id, 'target'], open_in_new_tab ? '_blank' : '_self'); |
|
42 | 58 | if (edit_link_command) { |
43 | 59 | edit_link_command.show_prompt = false; |
44 | 60 | } |
| 61 | + if (toggle_link_command) { |
| 62 | + toggle_link_command.show_prompt = false; |
| 63 | + } |
45 | 64 | svedit.focus_canvas(); |
46 | 65 | } |
47 | 66 |
|
|
64 | 83 | } |
65 | 84 |
|
66 | 85 | $effect(() => { |
67 | | - if (edit_link_command?.show_prompt && dialog_ref) { |
68 | | - href_input_value = target_node?.href || ''; |
69 | | - open_in_new_tab = target_node?.target === '_blank'; |
70 | | - dialog_ref.showModal(); |
| 86 | + if (is_open && dialog_ref) { |
| 87 | + href_input_value = is_creating ? 'https://' : target_node?.href || ''; |
| 88 | + open_in_new_tab = is_creating ? false : target_node?.target === '_blank'; |
| 89 | +
|
| 90 | + if (!dialog_ref.open) { |
| 91 | + dialog_ref.showModal(); |
| 92 | + } |
71 | 93 |
|
72 | 94 | if (href_input_ref) { |
73 | 95 | href_input_ref.focus(); |
|
81 | 103 |
|
82 | 104 | <dialog |
83 | 105 | bind:this={dialog_ref} |
84 | | - class="edit-link-dialog absolute z-40 m-0 mt-1 max-h-90 overflow-visible border border-(--border) bg-(--background) p-0 text-(--foreground) shadow-xl" |
85 | | - style="position-anchor: --{serialize_path( |
86 | | - path |
87 | | - )}; position-area: block-end span-all; justify-self: anchor-center;" |
| 106 | + class="edit-link-dialog absolute z-40 m-0 mt-3 max-h-90 overflow-hidden rounded-[23px] border border-(--border) bg-(--background) p-0 text-(--foreground) shadow-[0_1px_2px_rgb(0_0_0/0.12),0_4px_16px_rgb(0_0_0/0.08)]" |
| 107 | + style="position-anchor: {anchor_name}; position-area: block-end span-all; justify-self: anchor-center;" |
88 | 108 | onclick={handle_backdrop_click} |
89 | 109 | > |
90 | 110 | <div class="flex flex-col"> |
91 | 111 | <div class="px-1 pt-1"> |
92 | | - <div class="flex items-stretch"> |
| 112 | + <div |
| 113 | + class="flex items-center overflow-hidden rounded-full border border-(--border) focus-within:border-(--svedit-editing-stroke)" |
| 114 | + > |
93 | 115 | <input |
94 | 116 | id="edit-link-url-input" |
95 | 117 | bind:this={href_input_ref} |
96 | 118 | type="url" |
97 | 119 | bind:value={href_input_value} |
98 | 120 | placeholder="https://example.com" |
99 | | - class="edit-link-input w-72 min-w-0 flex-1 border border-(--border) bg-(--background) px-3 py-2 text-sm text-(--foreground) focus:border-(--svedit-editing-stroke) focus:shadow-none focus:ring-0 focus:outline-none" |
| 121 | + class="edit-link-input w-72 min-w-0 flex-1 border-0 bg-(--background) px-3 py-2 text-sm text-(--foreground) focus:shadow-none focus:ring-0 focus:outline-none" |
100 | 122 | onkeydown={handle_keydown} |
101 | 123 | /> |
102 | 124 | {#if app.has_backend} |
103 | 125 | <button |
104 | 126 | type="button" |
105 | | - class="shrink-0 cursor-pointer border border-(--border) border-l-transparent px-3 text-(--svedit-editing-stroke) hover:bg-(--muted) focus:border-(--svedit-editing-stroke) focus:shadow-none focus:ring-0 focus:outline-none" |
| 127 | + class="mr-0.5 flex size-9 shrink-0 cursor-pointer items-center justify-center rounded-full border-0 bg-transparent p-0 text-(--foreground) outline-none transition-all duration-150 hover:bg-(--muted) focus-visible:shadow-[inset_0_0_0_1px_var(--svedit-editing-stroke)] active:translate-y-px active:scale-95 active:bg-(--muted)" |
106 | 128 | title="Select page" |
107 | 129 | aria-label="Select page" |
108 | 130 | onclick={() => { |
|
114 | 136 | }} |
115 | 137 | > |
116 | 138 | <svg |
117 | | - class="size-4" |
| 139 | + class="size-6" |
118 | 140 | xmlns="http://www.w3.org/2000/svg" |
119 | | - viewBox="0 0 15 15" |
| 141 | + viewBox="0 0 24 24" |
120 | 142 | fill="none" |
121 | 143 | aria-hidden="true" |
122 | 144 | > |
123 | | - <rect x="1.5" y="1.5" width="5" height="5" rx="0.5" stroke="currentColor" /> |
124 | | - <rect x="8.5" y="1.5" width="5" height="5" rx="0.5" stroke="currentColor" /> |
125 | | - <rect x="1.5" y="8.5" width="5" height="5" rx="0.5" stroke="currentColor" /> |
126 | | - <rect x="8.5" y="8.5" width="5" height="5" rx="0.5" stroke="currentColor" /> |
| 145 | + <rect x="4.5" y="4.5" width="6" height="6" rx="1" stroke="currentColor" /> |
| 146 | + <rect x="13.5" y="4.5" width="6" height="6" rx="1" stroke="currentColor" /> |
| 147 | + <rect x="4.5" y="13.5" width="6" height="6" rx="1" stroke="currentColor" /> |
| 148 | + <rect x="13.5" y="13.5" width="6" height="6" rx="1" stroke="currentColor" /> |
127 | 149 | </svg> |
128 | 150 | </button> |
129 | 151 | {/if} |
130 | 152 | </div> |
131 | 153 | </div> |
132 | | - <div class="flex items-center justify-between px-3 py-2"> |
| 154 | + <div class="flex items-center justify-between p-1 pl-4"> |
133 | 155 | <label class="flex cursor-pointer items-center gap-2"> |
134 | 156 | <input |
135 | 157 | type="checkbox" |
136 | 158 | bind:checked={open_in_new_tab} |
137 | | - class="h-4 w-4 cursor-pointer text-(--svedit-editing-stroke) ring-0 focus:ring-0 focus-visible:ring-0 focus-visible:outline-1 focus-visible:outline-offset-1 focus-visible:outline-(--svedit-editing-stroke)" |
| 159 | + class="h-4 w-4 cursor-pointer rounded-full !border-(--border) !bg-(--muted) text-(--svedit-editing-stroke) ring-0 checked:!border-transparent checked:!bg-(--svedit-editing-stroke) focus:ring-0 focus:ring-offset-0 focus:shadow-none focus-visible:ring-0 focus-visible:ring-offset-0 focus-visible:outline-1 focus-visible:outline-offset-1 focus-visible:outline-(--svedit-editing-stroke)" |
138 | 160 | /> |
139 | 161 | <span class="text-sm text-(--foreground)">Open in new tab</span> |
140 | 162 | </label> |
141 | 163 | <button |
142 | 164 | type="button" |
143 | | - class="shrink-0 cursor-pointer text-sm text-(--svedit-editing-stroke) outline-1 outline-transparent hover:opacity-80 focus-visible:outline-1 focus-visible:outline-offset-1 focus-visible:outline-(--svedit-editing-stroke)" |
| 165 | + class="inline-flex h-9 shrink-0 cursor-pointer items-center justify-center rounded-full border-0 bg-transparent px-3 text-sm font-medium text-(--svedit-editing-stroke) outline-1 outline-transparent hover:bg-(--svedit-editing-fill) focus-visible:outline-1 focus-visible:outline-offset-1 focus-visible:outline-(--svedit-editing-stroke)" |
144 | 166 | onclick={save} |
145 | 167 | > |
146 | | - UPDATE |
| 168 | + {is_new_link ? 'Create' : 'Update'} |
147 | 169 | </button> |
148 | 170 | </div> |
149 | 171 | </div> |
|
0 commit comments