fix: standardize Edra editor placeholder widths and slash command navigation

- Fix slash command keyboard navigation by uncommenting handler
- Update all media placeholders to respect content block margins (2.25rem)
- Refactor placeholder styles to use SCSS variables consistently
- Fix Audio, Gallery, IFrame, Video, Location, and URL embed placeholders
- Fix Image placeholder width to match other placeholders
- Ensure responsive margins on mobile (2rem)
This commit is contained in:
Justin Edmund 2025-06-26 15:37:47 -04:00
parent 22c27a0e64
commit 48cc27770f
8 changed files with 387 additions and 167 deletions

View file

@ -219,8 +219,8 @@ export default (menuList: Component<any, any, ''>): Extension =>
if (props.event.key === 'Enter') return true if (props.event.key === 'Enter') return true
// return component.ref?.onKeyDown(props); return component.ref?.onKeyDown(props);
return false // return false
}, },
onExit(props) { onExit(props) {

View file

@ -15,16 +15,73 @@
} }
</script> </script>
<NodeViewWrapper class="edra-media-placeholder-wrapper" contenteditable="false"> <NodeViewWrapper class="edra-audio-placeholder-wrapper" contenteditable="false">
<!-- svelte-ignore a11y_click_events_have_key_events --> <!-- svelte-ignore a11y_click_events_have_key_events -->
<span <div class="edra-audio-placeholder-container">
class="edra-media-placeholder-content" <button
onclick={handleClick} class="edra-audio-placeholder-content"
tabindex="0" onclick={handleClick}
role="button" tabindex="0"
aria-label="Insert An Audio" aria-label="Insert An Audio"
> >
<AudioLines class="edra-media-placeholder-icon" /> <AudioLines class="edra-audio-placeholder-icon" />
<span class="edra-media-placeholder-text">Insert An Audio</span> <span class="edra-audio-placeholder-text">Insert An Audio</span>
</span> </button>
</div>
</NodeViewWrapper> </NodeViewWrapper>
<style lang="scss">
@import '$styles/variables';
.edra-audio-placeholder-wrapper {
width: 100%;
margin-bottom: 1rem;
}
.edra-audio-placeholder-container {
margin-left: 2.25rem;
margin-right: 2.25rem;
@media (max-width: 768px) {
margin-left: 2rem;
margin-right: 2rem;
}
}
.edra-audio-placeholder-content {
width: 100%;
padding: $unit-3x;
background-color: $gray-95;
border: 2px dashed $gray-85;
border-radius: $corner-radius;
display: flex;
align-items: center;
justify-content: center;
gap: $unit-2x;
cursor: pointer;
transition: all 0.2s ease;
color: $gray-50;
&:hover {
background-color: $gray-90;
border-color: $gray-70;
color: $gray-40;
}
&:focus {
outline: none;
border-color: $primary-color;
box-shadow: 0 0 0 3px rgba($primary-color, 0.1);
}
}
:global(.edra-audio-placeholder-icon) {
width: $unit-3x;
height: $unit-3x;
}
.edra-audio-placeholder-text {
font-size: $font-size-small;
font-weight: 500;
}
</style>

View file

@ -224,64 +224,78 @@
/> />
</NodeViewWrapper> </NodeViewWrapper>
<style> <style lang="scss">
@import '$styles/variables';
.edra-media-placeholder-wrapper {
width: 100%;
margin-bottom: 1rem;
margin-left: 2.25rem;
margin-right: 2.25rem;
@media (max-width: 768px) {
margin-left: 2rem;
margin-right: 2rem;
}
}
.edra-media-placeholder-container { .edra-media-placeholder-container {
display: flex; display: flex;
gap: 12px; gap: $unit-2x;
padding: 24px; padding: $unit-3x;
border: 2px dashed #e5e7eb; border: 2px dashed $gray-85;
border-radius: 8px; border-radius: $corner-radius;
background: #f9fafb; background: $gray-95;
transition: all 0.2s ease; transition: all 0.2s ease;
justify-content: center; justify-content: center;
align-items: center; align-items: center;
min-height: 80px; min-height: 80px;
}
.edra-media-placeholder-container:hover { &:hover {
border-color: #d1d5db; border-color: $gray-70;
background: #f3f4f6; background: $gray-90;
}
} }
.edra-media-placeholder-option { .edra-media-placeholder-option {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
align-items: center; align-items: center;
gap: 8px; gap: $unit;
padding: 16px 20px; padding: $unit-2x $unit-3x;
border: 1px solid #e5e7eb; border: 1px solid $gray-85;
border-radius: 6px; border-radius: $corner-radius-sm;
background: white; background: $white;
cursor: pointer; cursor: pointer;
transition: all 0.2s ease; transition: all 0.2s ease;
min-width: 140px; min-width: 140px;
}
.edra-media-placeholder-option:hover { &:hover {
border-color: #d1d5db; border-color: $gray-70;
background: #f9fafb; background: $gray-95;
transform: translateY(-1px); transform: translateY(-1px);
} }
.edra-media-placeholder-option:focus { &:focus {
outline: none; outline: none;
border-color: #3b82f6; border-color: $primary-color;
box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1); box-shadow: 0 0 0 3px rgba($primary-color, 0.1);
}
} }
.edra-media-placeholder-uploading { .edra-media-placeholder-uploading {
display: flex; display: flex;
align-items: center; align-items: center;
gap: 8px; gap: $unit;
padding: 20px; padding: $unit-3x;
color: #6b7280; color: $gray-50;
} }
.spinner { .spinner {
width: 16px; width: $unit-2x;
height: 16px; height: $unit-2x;
border: 2px solid #f3f4f6; border: 2px solid $gray-90;
border-top: 2px solid #3b82f6; border-top: 2px solid $primary-color;
border-radius: 50%; border-radius: 50%;
animation: spin 1s linear infinite; animation: spin 1s linear infinite;
} }
@ -296,14 +310,14 @@
} }
:global(.edra-media-placeholder-icon) { :global(.edra-media-placeholder-icon) {
width: 28px; width: $unit-3x + $unit-half;
height: 28px; height: $unit-3x + $unit-half;
color: #6b7280; color: $gray-50;
} }
.edra-media-placeholder-text { .edra-media-placeholder-text {
font-size: 14px; font-size: $font-size-small;
color: #6b7280; color: $gray-50;
font-weight: 500; font-weight: 500;
} }
</style> </style>

View file

@ -163,63 +163,77 @@
/> />
</NodeViewWrapper> </NodeViewWrapper>
<style> <style lang="scss">
@import '$styles/variables';
.edra-gallery-placeholder-wrapper {
width: 100%;
margin-bottom: 1rem;
margin-left: 2.25rem;
margin-right: 2.25rem;
@media (max-width: 768px) {
margin-left: 2rem;
margin-right: 2rem;
}
}
.edra-gallery-placeholder-container { .edra-gallery-placeholder-container {
display: flex; display: flex;
gap: 12px; gap: $unit-2x;
padding: 24px; padding: $unit-3x;
border: 2px dashed #e5e7eb; border: 2px dashed $gray-85;
border-radius: 8px; border-radius: $corner-radius;
background: #f9fafb; background: $gray-95;
transition: all 0.2s ease; transition: all 0.2s ease;
justify-content: center; justify-content: center;
align-items: center; align-items: center;
}
.edra-gallery-placeholder-container:hover { &:hover {
border-color: #d1d5db; border-color: $gray-70;
background: #f3f4f6; background: $gray-90;
}
} }
.edra-gallery-placeholder-option { .edra-gallery-placeholder-option {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
align-items: center; align-items: center;
gap: 8px; gap: $unit;
padding: 16px 20px; padding: $unit-2x $unit-3x;
border: 1px solid #e5e7eb; border: 1px solid $gray-85;
border-radius: 6px; border-radius: $corner-radius-sm;
background: white; background: $white;
cursor: pointer; cursor: pointer;
transition: all 0.2s ease; transition: all 0.2s ease;
min-width: 140px; min-width: 140px;
}
.edra-gallery-placeholder-option:hover { &:hover {
border-color: #d1d5db; border-color: $gray-70;
background: #f9fafb; background: $gray-95;
transform: translateY(-1px); transform: translateY(-1px);
} }
.edra-gallery-placeholder-option:focus { &:focus {
outline: none; outline: none;
border-color: #3b82f6; border-color: $primary-color;
box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1); box-shadow: 0 0 0 3px rgba($primary-color, 0.1);
}
} }
.edra-gallery-placeholder-uploading { .edra-gallery-placeholder-uploading {
display: flex; display: flex;
align-items: center; align-items: center;
gap: 8px; gap: $unit;
padding: 20px; padding: $unit-3x;
color: #6b7280; color: $gray-50;
} }
.spinner { .spinner {
width: 16px; width: $unit-2x;
height: 16px; height: $unit-2x;
border: 2px solid #f3f4f6; border: 2px solid $gray-90;
border-top: 2px solid #3b82f6; border-top: 2px solid $primary-color;
border-radius: 50%; border-radius: 50%;
animation: spin 1s linear infinite; animation: spin 1s linear infinite;
} }
@ -234,14 +248,14 @@
} }
:global(.edra-gallery-placeholder-icon) { :global(.edra-gallery-placeholder-icon) {
width: 28px; width: $unit-3x + $unit-half;
height: 28px; height: $unit-3x + $unit-half;
color: #6b7280; color: $gray-50;
} }
.edra-gallery-placeholder-text { .edra-gallery-placeholder-text {
font-size: 14px; font-size: $font-size-small;
color: #6b7280; color: $gray-50;
font-weight: 500; font-weight: 500;
} }
</style> </style>

View file

@ -117,49 +117,61 @@
</NodeViewWrapper> </NodeViewWrapper>
<style lang="scss"> <style lang="scss">
@import '$styles/variables';
:global(.node-geolocationPlaceholder) {
margin-bottom: 1rem;
margin-left: 2.25rem;
margin-right: 2.25rem;
@media (max-width: 768px) {
margin-left: 2rem;
margin-right: 2rem;
}
}
.geolocation-placeholder { .geolocation-placeholder {
background: #f8f9fa; background: $gray-95;
border: 2px dashed #e0e0e0; border: 2px dashed $gray-85;
border-radius: 8px; border-radius: $corner-radius;
padding: 24px; padding: $unit-3x;
margin: 16px 0;
text-align: center; text-align: center;
} }
.icon { .icon {
display: flex; display: flex;
justify-content: center; justify-content: center;
margin-bottom: 16px; margin-bottom: $unit-2x;
color: #6b7280; color: $gray-50;
} }
.content { .content {
h3 { h3 {
margin: 0 0 8px; margin: 0 0 $unit;
font-size: 18px; font-size: $font-size-large;
font-weight: 600; font-weight: 600;
color: #1f2937; color: $gray-10;
} }
p { p {
margin: 0 0 16px; margin: 0 0 $unit-2x;
color: #6b7280; color: $gray-50;
} }
} }
.configure-btn { .configure-btn {
background: #3b82f6; background: $primary-color;
color: white; color: $white;
border: none; border: none;
border-radius: 6px; border-radius: $corner-radius-sm;
padding: 8px 16px; padding: $unit $unit-2x;
font-size: 14px; font-size: $font-size-small;
font-weight: 500; font-weight: 500;
cursor: pointer; cursor: pointer;
transition: background-color 0.2s; transition: background-color 0.2s;
&:hover { &:hover {
background: #2563eb; background: darken($primary-color, 10%);
} }
} }

View file

@ -15,16 +15,73 @@
} }
</script> </script>
<NodeViewWrapper class="edra-media-placeholder-wrapper" contenteditable={false} spellcheck={false}> <NodeViewWrapper class="edra-iframe-placeholder-wrapper" contenteditable={false} spellcheck={false}>
<!-- svelte-ignore a11y_click_events_have_key_events --> <!-- svelte-ignore a11y_click_events_have_key_events -->
<span <div class="edra-iframe-placeholder-container">
class="edra-media-placeholder-content" <button
onclick={handleClick} class="edra-iframe-placeholder-content"
tabindex="0" onclick={handleClick}
role="button" tabindex="0"
aria-label="Insert An Audio" aria-label="Insert An IFrame"
> >
<CodeXML class="edra-media-placeholder-icon" /> <CodeXML class="edra-iframe-placeholder-icon" />
<span class="edra-media-placeholder-text">Insert An IFrame</span> <span class="edra-iframe-placeholder-text">Insert An IFrame</span>
</span> </button>
</div>
</NodeViewWrapper> </NodeViewWrapper>
<style lang="scss">
@import '$styles/variables';
.edra-iframe-placeholder-wrapper {
width: 100%;
margin-bottom: 1rem;
}
.edra-iframe-placeholder-container {
margin-left: 2.25rem;
margin-right: 2.25rem;
@media (max-width: 768px) {
margin-left: 2rem;
margin-right: 2rem;
}
}
.edra-iframe-placeholder-content {
width: 100%;
padding: $unit-3x;
background-color: $gray-95;
border: 2px dashed $gray-85;
border-radius: $corner-radius;
display: flex;
align-items: center;
justify-content: center;
gap: $unit-2x;
cursor: pointer;
transition: all 0.2s ease;
color: $gray-50;
&:hover {
background-color: $gray-90;
border-color: $gray-70;
color: $gray-40;
}
&:focus {
outline: none;
border-color: $primary-color;
box-shadow: 0 0 0 3px rgba($primary-color, 0.1);
}
}
:global(.edra-iframe-placeholder-icon) {
width: $unit-3x;
height: $unit-3x;
}
.edra-iframe-placeholder-text {
font-size: $font-size-small;
font-weight: 500;
}
</style>

View file

@ -150,46 +150,55 @@
</NodeViewWrapper> </NodeViewWrapper>
<style lang="scss"> <style lang="scss">
@import '$styles/variables';
.edra-url-embed-placeholder-wrapper { .edra-url-embed-placeholder-wrapper {
margin: 1rem 0; margin-bottom: 1rem;
margin-left: 2.25rem;
margin-right: 2.25rem;
@media (max-width: 768px) {
margin-left: 2rem;
margin-right: 2rem;
}
} }
.url-input-container { .url-input-container {
display: flex; display: flex;
gap: 0.5rem; gap: $unit-half;
padding: 1rem; padding: $unit-2x;
background: var(--grey-95, #f8f9fa); background: $gray-95;
border: 2px solid var(--grey-85, #e9ecef); border: 2px solid $gray-85;
border-radius: 8px; border-radius: $corner-radius;
} }
.url-input { .url-input {
flex: 1; flex: 1;
padding: 0.5rem 1rem; padding: $unit $unit-2x;
border: 1px solid var(--grey-80, #dee2e6); border: 1px solid $gray-80;
border-radius: 6px; border-radius: $corner-radius-sm;
font-size: 0.875rem; font-size: $font-size-small;
background: white; background: $white;
&:focus { &:focus {
outline: none; outline: none;
border-color: var(--primary-color, #3b82f6); border-color: $primary-color;
} }
} }
.submit-button { .submit-button {
padding: 0.5rem 1rem; padding: $unit $unit-2x;
background: var(--primary-color, #3b82f6); background: $primary-color;
color: white; color: $white;
border: none; border: none;
border-radius: 6px; border-radius: $corner-radius-sm;
font-size: 0.875rem; font-size: $font-size-small;
font-weight: 500; font-weight: 500;
cursor: pointer; cursor: pointer;
transition: background-color 0.2s; transition: background-color 0.2s;
&:hover:not(:disabled) { &:hover:not(:disabled) {
background: var(--primary-hover, #2563eb); background: darken($primary-color, 10%);
} }
&:disabled { &:disabled {
@ -203,17 +212,17 @@
flex-direction: column; flex-direction: column;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
gap: 0.5rem; gap: $unit-half;
padding: 2rem; padding: $unit-3x;
border: 2px dashed var(--grey-80, #dee2e6); border: 2px dashed $gray-85;
border-radius: 8px; border-radius: $corner-radius;
background: var(--grey-95, #f8f9fa); background: $gray-95;
cursor: pointer; cursor: pointer;
transition: all 0.2s ease; transition: all 0.2s ease;
&:hover:not(.loading):not(.error) { &:hover:not(.loading):not(.error) {
border-color: var(--grey-60, #adb5bd); border-color: $gray-70;
background: var(--grey-90, #e9ecef); background: $gray-90;
} }
&.loading { &.loading {
@ -221,47 +230,47 @@
} }
&.error { &.error {
border-color: var(--red-60, #dc3545); border-color: $red-60;
background: #fee; background: #fee;
cursor: default; cursor: default;
} }
} }
.placeholder-icon { .placeholder-icon {
width: 32px; width: $unit-4x;
height: 32px; height: $unit-4x;
color: var(--grey-50, #6c757d); color: $gray-50;
} }
.error .placeholder-icon { .error .placeholder-icon {
color: var(--red-60, #dc3545); color: $red-60;
} }
.placeholder-text { .placeholder-text {
font-size: 0.875rem; font-size: $font-size-small;
color: var(--grey-30, #495057); color: $gray-30;
} }
.error-content { .error-content {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
align-items: center; align-items: center;
gap: 0.5rem; gap: $unit-half;
} }
.retry-button { .retry-button {
padding: 0.25rem 0.75rem; padding: $unit-half $unit-2x;
background: transparent; background: transparent;
color: var(--red-60, #dc3545); color: $red-60;
border: 1px solid var(--red-60, #dc3545); border: 1px solid $red-60;
border-radius: 4px; border-radius: $corner-radius-xs;
font-size: 0.75rem; font-size: $font-size-extra-small;
cursor: pointer; cursor: pointer;
transition: all 0.2s; transition: all 0.2s;
&:hover { &:hover {
background: var(--red-60, #dc3545); background: $red-60;
color: white; color: $white;
} }
} }

View file

@ -15,16 +15,73 @@
} }
</script> </script>
<NodeViewWrapper class="edra-media-placeholder-wrapper" contenteditable="false"> <NodeViewWrapper class="edra-video-placeholder-wrapper" contenteditable="false">
<!-- svelte-ignore a11y_click_events_have_key_events --> <!-- svelte-ignore a11y_click_events_have_key_events -->
<span <div class="edra-video-placeholder-container">
class="edra-media-placeholder-content" <button
onclick={handleClick} class="edra-video-placeholder-content"
tabindex="0" onclick={handleClick}
role="button" tabindex="0"
aria-label="Insert A Video" aria-label="Insert A Video"
> >
<Video class="edra-media-placeholder-icon" /> <Video class="edra-video-placeholder-icon" />
<span class="edra-media-placeholder-text">Insert A Video</span> <span class="edra-video-placeholder-text">Insert A Video</span>
</span> </button>
</div>
</NodeViewWrapper> </NodeViewWrapper>
<style lang="scss">
@import '$styles/variables';
.edra-video-placeholder-wrapper {
width: 100%;
margin-bottom: 1rem;
}
.edra-video-placeholder-container {
margin-left: 2.25rem;
margin-right: 2.25rem;
@media (max-width: 768px) {
margin-left: 2rem;
margin-right: 2rem;
}
}
.edra-video-placeholder-content {
width: 100%;
padding: $unit-3x;
background-color: $gray-95;
border: 2px dashed $gray-85;
border-radius: $corner-radius;
display: flex;
align-items: center;
justify-content: center;
gap: $unit-2x;
cursor: pointer;
transition: all 0.2s ease;
color: $gray-50;
&:hover {
background-color: $gray-90;
border-color: $gray-70;
color: $gray-40;
}
&:focus {
outline: none;
border-color: $primary-color;
box-shadow: 0 0 0 3px rgba($primary-color, 0.1);
}
}
:global(.edra-video-placeholder-icon) {
width: $unit-3x;
height: $unit-3x;
}
.edra-video-placeholder-text {
font-size: $font-size-small;
font-weight: 500;
}
</style>