mirror of
https://github.com/shoelace-style/webawesome.git
synced 2026-01-12 12:09:26 +00:00
* Basic scaffolding * Generate theme & palette data.js that other JS can import * Make it possible to include page-card without links * WIP * Add `appearance` to details, closes #569 Except `accent` as that's a) far less useful and b) trickier due to the icon color * Fix broken link * WIP * WIP * Icons icon * Unify styles for interactive cards * Prevent focusing inside theme icons * Fixes * Action page cards * Panel scrollables * scrollable * Scroll shadows * Add renaming UI * UI * Move styling of heading icons to `ui.css` * Support permalinks & CRUD * Make clickable cards more accessible * Style cards a little better * Default to styles panel if theme is selected * Update theme-icons.css * Custom themes should be saved under Custom * Get theme code * Bigger title * Fixes * Use theme Vue app for remixing too * Fix preview jank and make preview script more flexible * Make radio groups scrollable * Add affordance to button cards * Sticky * `<color-select>` * Fix theme remixing * Improve previewing logic * Fix preview * Move `domChange()` to separate module `theme-picker.js` includes side-effects, which may not always be desirable everywhere we may want to import `domChange()` * Update preview.js * Panel animation * Hide Save button if no changes and not saved * Do not show blank code when no selection has been made * Use theme slug in filename * Remove unused component * Better UI for editing title (and any other text) * Tweak UI of renaming * Better indicate default selection * Fix preview reverting bug * Fill out app preview with more examples * Remove `zoom` from theme showcase (yields unexpected/painful results Safari), improve display in wider viewports * Pending delete * Make styles panel cards scrollable * Fix some of the Safari issues * Update search.css * Update panel.css * Select preview UI * Fix typo * Frame colors setting as color contrast * Show dark mode in color mappings * Brand color * Swatch styling * Fix caret icon * Move Starting theme to the same level as other controls * Rename typography to Fonts * Fix bug: Swatch select should show swatches from the selected palette * Move capitalize to shared utils * Add utils for handling nested objects * Icons panel * Update code.js * Move utils around * Add fit and finish to sidebar panels * Theme card: Move icons to separate data structure * Move data to dedicated folder since we now have a lot more of it * Add default icon families and variants to themes * Data * Add `deepEntries()` * Add Duotone * Spruce up icons preview * Use theme's icon family in showcase * Font cards * Font cards * Add `max-inline-size` to preview container * Remove alternate preview options * Remove theme subtitle * Support FA kit codes * Remove Pro badges from theme cards * Use panagram preview for Fonts * Consistent heading and label capitalization * Classes for different icons-card types * Update data.js.njk * Variable style on icon family cards * Fix Sharp Duotone * Clean up FA kit code hint * Hide non-functional Icon Library field * Fix theme icon heights * icon variant -> style in theme metadata * Fix bug with icons defaults not being shown * More convenient theme defaults * Fix bug with non updating URL * Fix bug * Fix multiplying badges * Custom docs pages * Add Duotone icons to Mellow theme * Fix 404 * Remove "Create" from sidebar * Fix bug * Move vue components to `/assets/`, move their CSS with them * Safari/FF compatibility * Make panels scrollable again * Fix extra spacing --------- Co-authored-by: lindsaym-fa <dev@lindsaym.design>
173 lines
3.5 KiB
JavaScript
173 lines
3.5 KiB
JavaScript
const my = (globalThis.my = new EventTarget());
|
|
export default my;
|
|
|
|
class PersistedArray extends Array {
|
|
constructor(key) {
|
|
super();
|
|
this.key = key;
|
|
|
|
if (this.key) {
|
|
this.fromLocalStorage();
|
|
}
|
|
|
|
// Items were updated in another tab
|
|
addEventListener('storage', event => {
|
|
if (event.key === this.key || !event.key) {
|
|
this.fromLocalStorage();
|
|
}
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Update data from local storage
|
|
*/
|
|
fromLocalStorage() {
|
|
// First, empty the array
|
|
this.splice(0, this.length);
|
|
|
|
// Then, fill it with the data from local storage
|
|
let saved = localStorage[this.key] ? JSON.parse(localStorage[this.key]) : null;
|
|
|
|
if (saved) {
|
|
this.push(...saved);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Write data to local storage
|
|
*/
|
|
toLocalStorage() {
|
|
if (this.length > 0) {
|
|
localStorage[this.key] = JSON.stringify(this);
|
|
} else {
|
|
delete localStorage[this.key];
|
|
}
|
|
}
|
|
}
|
|
|
|
class SavedEntities extends EventTarget {
|
|
constructor({ key, type, url }) {
|
|
super();
|
|
this.key = key;
|
|
this.type = type;
|
|
this.url = url ?? type + 's';
|
|
this.saved = new PersistedArray(key);
|
|
|
|
let all = this;
|
|
this.entityPrototype = {
|
|
type: this.type,
|
|
baseUrl: this.baseUrl,
|
|
|
|
get url() {
|
|
return all.getURL(this);
|
|
},
|
|
|
|
get parentUrl() {
|
|
return all.getParentURL(this);
|
|
},
|
|
|
|
delete() {
|
|
all.delete(this);
|
|
},
|
|
};
|
|
}
|
|
|
|
getUid() {
|
|
if (this.saved.length === 0) {
|
|
return 1;
|
|
}
|
|
|
|
let uids = new Set(this.saved.map(p => p.uid));
|
|
|
|
// Find first available number
|
|
for (let i = 1; i <= this.saved.length + 1; i++) {
|
|
if (!uids.has(i)) {
|
|
return i;
|
|
}
|
|
}
|
|
}
|
|
|
|
get baseUrl() {
|
|
return `/docs/${this.url}/`;
|
|
}
|
|
|
|
getURL(entity) {
|
|
return this.getParentURL(entity) + entity.search;
|
|
}
|
|
|
|
getParentURL(entity) {
|
|
return this.baseUrl + entity.id + '/';
|
|
}
|
|
|
|
getObject(entity) {
|
|
let ret = Object.create(this.entityPrototype, Object.getOwnPropertyDescriptors(entity));
|
|
// debugger;
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* Save an entity, either by updating its existing entry or creating a new one
|
|
* @param {object} entity
|
|
*/
|
|
save(entity) {
|
|
if (!entity.uid) {
|
|
// First time saving
|
|
entity.uid = this.getUid();
|
|
}
|
|
|
|
let savedPalettes = this.saved;
|
|
let existingIndex = entity.uid ? this.saved.findIndex(p => p.uid === entity.uid) : -1;
|
|
let newIndex = existingIndex > -1 ? existingIndex : savedPalettes.length;
|
|
|
|
this.saved.splice(newIndex, 1, entity);
|
|
|
|
this.saved.toLocalStorage();
|
|
|
|
this.dispatchEvent(new CustomEvent('save', { detail: this.getObject(entity) }));
|
|
|
|
return entity;
|
|
}
|
|
|
|
delete(entity) {
|
|
let count = this.saved.length;
|
|
|
|
if (count === 0 || !entity?.uid) {
|
|
// No stored entities or this entity has not been saved
|
|
return;
|
|
}
|
|
|
|
// TODO improve UX of this
|
|
if (!confirm(`Are you sure you want to delete ${this.type} “${entity.title}”?`)) {
|
|
return;
|
|
}
|
|
|
|
for (let index; (index = this.saved.findIndex(p => p.uid === entity.uid)) > -1; ) {
|
|
this.saved.splice(index, 1);
|
|
}
|
|
|
|
if (this.saved.length === count) {
|
|
// Nothing was removed
|
|
return;
|
|
}
|
|
|
|
this.saved.toLocalStorage();
|
|
|
|
this.dispatchEvent(new CustomEvent('delete', { detail: this.getObject(entity) }));
|
|
}
|
|
|
|
dispatchEvent(event) {
|
|
super.dispatchEvent(event);
|
|
my.dispatchEvent(event);
|
|
}
|
|
}
|
|
|
|
my.palettes = new SavedEntities({
|
|
key: 'savedPalettes',
|
|
type: 'palette',
|
|
});
|
|
|
|
my.themes = new SavedEntities({
|
|
key: 'savedThemes',
|
|
type: 'theme',
|
|
});
|