atomic-server
atomic-server copied to clipboard
Improved CMS capabilities - edit content from a webpage
We're now using AtomicServer + front-end frameworks (sveltekit, astro) in production for a couple of customers, and I think there is one common usecase that requires some improvement: see a resource in your deployed website, and decide you want to change it.
Let's dive into how we can improve this:
Browser extension with editing capabilities
When the browser extension is installed, user can hover over a resource to see an edit button. Clicking that opens a resource form overlay. The extension manages the secret of the Agent. The extension queries the dom for some attribute (e.g atomic-subject) and injects a button on hover.
- Requires user to install an extension
- Requires us to manage another app / publish extension in multiple stores
Add alt-click action to compiled front-end
When the user holds the alt or option key, show borders of resources (can be the same atomic-subject) on hover. Clicking opens that resource on atomicdata.dev in edit mode in a new tab.
- Elegant, simple solution
- Takes over the
altkeys default behavior, can be odd to users who aren't admins - Can be forgotten by admins
---
/**
* A wrapper component that enables alt+click editing functionality for Atomic Data resources.
* When holding Alt, the wrapped content will show an outline and clicking will redirect to the edit page.
*
* @component
* @example
* ```astro
* <ResourceClickWrapper subject="https://example.com/resource">
* <SomeContent />
* </ResourceClickWrapper>
* ```
*/
type Props = {
subject: string;
};
const { subject } = Astro.props;
const editLink = `https://atomicdata.dev/app/edit?subject=${subject}`;
---
<div class='block-container' data-edit-link={editLink}>
<slot />
</div>
<script>
const blocks = document.querySelectorAll('.block-container');
const toggleAltClass = (show: boolean) =>
blocks.forEach(el => el.classList.toggle('alt-active', show));
document.addEventListener('keydown', (e: KeyboardEvent) =>
toggleAltClass(e.altKey),
);
document.addEventListener('keyup', (e: KeyboardEvent) =>
toggleAltClass(e.altKey),
);
window.addEventListener('blur', () => toggleAltClass(false));
window.addEventListener('focus', e => toggleAltClass(e.altKey));
blocks.forEach(el =>
el.addEventListener('click', (e: MouseEvent) => {
if (e.altKey)
window.location.href = el.getAttribute('data-edit-link') || '';
}),
);
</script>
<style>
.block-container.alt-active {
outline: 2px dashed #666;
cursor: pointer;
}
.block-container.alt-active:hover {
outline-color: blue;
background-color: rgba(0, 0, 0, 0.03);
}
</style>
How about this?
The extension doesn't need to manage an agent or have any settings or even a UI (Maybe only for usage instructions). When the user clicks the extension icon a script will be injected in the current tab. The script will look for any nodes with a data-atomic-subject attribute, measure it's dimensions using getBoundingClientRect and overlay an element with an outline on top. Then when clicked the user navigates to the subject in the attribute (to [domain]/edit?subject=[subject]).
Since we don't edit in the extension it self we don't need an agent, or even use @tomic/lib at all.
We could also publish this script on a cdn and have the developer include it on the page instead. Personally I'd go for the extension because I don't like including dev/admin stuff in a production app. It's also means every visitor will send a request to a cdn for a script that doesn't get used by them att all
--- /** * A wrapper component that enables alt+click editing functionality for Atomic Data resources. * When holding Alt, the wrapped content will show an outline and clicking will redirect to the edit page. * * @component * @example * ```astro * <ResourceClickWrapper subject="https://example.com/resource"> * <SomeContent /> * </ResourceClickWrapper> * ``` */ type Props = { subject: string; }; const { subject } = Astro.props; const editLink = `https://atomicdata.dev/app/edit?subject=${subject}`; --- <div class='block-container' data-edit-link={editLink}> <slot /> </div> <script> const blocks = document.querySelectorAll('.block-container'); const toggleAltClass = (show: boolean) => blocks.forEach(el => el.classList.toggle('alt-active', show)); document.addEventListener('keydown', (e: KeyboardEvent) => toggleAltClass(e.altKey), ); document.addEventListener('keyup', (e: KeyboardEvent) => toggleAltClass(e.altKey), ); window.addEventListener('blur', () => toggleAltClass(false)); window.addEventListener('focus', e => toggleAltClass(e.altKey)); blocks.forEach(el => el.addEventListener('click', (e: MouseEvent) => { if (e.altKey) window.location.href = el.getAttribute('data-edit-link') || ''; }), ); </script> <style> .block-container.alt-active { outline: 2px dashed #666; cursor: pointer; } .block-container.alt-active:hover { outline-color: blue; background-color: rgba(0, 0, 0, 0.03); } </style>How about this?
This is to specific for astro. We should make it generic so it works with every possible framework
Hmm yeah. Would be better to make it generic.