feat: scaffold Astro + Tailwind project

This commit is contained in:
TerryM
2026-05-12 16:16:03 +08:00
parent 906eb5c763
commit 03d3800c6c
12097 changed files with 1266600 additions and 0 deletions

View File

@@ -0,0 +1,233 @@
import { loadDevToolbarApps } from "astro:toolbar:internal";
import { ToolbarAppEventTarget } from "./helpers.js";
import { settings } from "./settings.js";
let overlay;
document.addEventListener("DOMContentLoaded", async () => {
const [
customAppsDefinitions,
{ default: astroDevToolApp },
{ default: astroAuditApp },
{ default: astroXrayApp },
{ default: astroSettingsApp },
{ AstroDevToolbar, DevToolbarCanvas, getAppIcon },
{
DevToolbarCard,
DevToolbarHighlight,
DevToolbarTooltip,
DevToolbarWindow,
DevToolbarToggle,
DevToolbarButton,
DevToolbarBadge,
DevToolbarIcon,
DevToolbarSelect,
DevToolbarRadioCheckbox
}
] = await Promise.all([
loadDevToolbarApps(),
import("./apps/astro.js"),
import("./apps/audit/index.js"),
import("./apps/xray.js"),
import("./apps/settings.js"),
import("./toolbar.js"),
import("./ui-library/index.js")
]);
customElements.define("astro-dev-toolbar", AstroDevToolbar);
customElements.define("astro-dev-toolbar-window", DevToolbarWindow);
customElements.define("astro-dev-toolbar-app-canvas", DevToolbarCanvas);
customElements.define("astro-dev-toolbar-tooltip", DevToolbarTooltip);
customElements.define("astro-dev-toolbar-highlight", DevToolbarHighlight);
customElements.define("astro-dev-toolbar-card", DevToolbarCard);
customElements.define("astro-dev-toolbar-toggle", DevToolbarToggle);
customElements.define("astro-dev-toolbar-button", DevToolbarButton);
customElements.define("astro-dev-toolbar-badge", DevToolbarBadge);
customElements.define("astro-dev-toolbar-icon", DevToolbarIcon);
customElements.define("astro-dev-toolbar-select", DevToolbarSelect);
customElements.define("astro-dev-toolbar-radio-checkbox", DevToolbarRadioCheckbox);
overlay = document.createElement("astro-dev-toolbar");
const notificationLevels = ["error", "warning", "info"];
const notificationSVGs = {
error: '<svg viewBox="0 0 10 10" style="--fill:var(--fill-default);--fill-default:#B33E66;--fill-hover:#E3AFC1;"><rect width="9" height="9" x=".5" y=".5" fill="var(--fill)" stroke="#13151A" stroke-width="2" rx="4.5"/></svg>',
warning: '<svg width="12" height="10" fill="none" style="--fill:var(--fill-default);--fill-default:#B58A2D;--fill-hover:#D5B776;"><path fill="var(--fill)" stroke="#13151A" stroke-width="2" d="M7.29904 1.25c-.57735-1-2.02073-1-2.59808 0l-3.4641 6C.65951 8.25 1.3812 9.5 2.5359 9.5h6.9282c1.1547 0 1.8764-1.25 1.299-2.25l-3.46406-6Z"/></svg>',
info: '<svg viewBox="0 0 10 10" style="--fill:var(--fill-default);--fill-default:#3645D9;--fill-hover:#BDC3FF;"><rect width="9" height="9" x=".5" y=".5" fill="var(--fill)" stroke="#13151A" stroke-width="2" rx="1.5"/></svg>'
};
const prepareApp = (appDefinition, builtIn) => {
const eventTarget = new ToolbarAppEventTarget();
const app = {
...appDefinition,
builtIn,
active: false,
status: "loading",
notification: { state: false, level: void 0 },
eventTarget
};
eventTarget.addEventListener("toggle-notification", (evt) => {
if (!(evt instanceof CustomEvent)) return;
const target = overlay.shadowRoot?.querySelector(`[data-app-id="${app.id}"]`);
if (!target) return;
const notificationElement = target.querySelector(".notification");
if (!notificationElement) return;
let newState = evt.detail.state ?? true;
let level = notificationLevels.includes(evt?.detail?.level) ? evt.detail.level : "error";
app.notification.state = newState;
if (newState) app.notification.level = level;
notificationElement.toggleAttribute("data-active", newState);
if (newState) {
notificationElement.setAttribute("data-level", level);
notificationElement.innerHTML = notificationSVGs[level];
}
});
const onToggleApp = async (evt) => {
let newState = void 0;
if (evt instanceof CustomEvent) {
newState = evt.detail.state ?? true;
}
await overlay.setAppStatus(app, newState);
};
eventTarget.addEventListener("toggle-app", onToggleApp);
return app;
};
const astroMoreApp = {
id: "astro:more",
name: "More",
icon: "dots-three",
init(canvas, eventTarget) {
const hiddenApps = apps.filter((p) => !p.builtIn).slice(overlay.customAppsToShow);
createDropdown();
document.addEventListener("astro:after-swap", createDropdown);
function createDropdown() {
const style = document.createElement("style");
style.innerHTML = `
#dropdown {
background: rgba(19, 21, 26, 1);
border: 1px solid rgba(52, 56, 65, 1);
border-radius: 12px;
box-shadow: 0px 0px 0px 0px rgba(19, 21, 26, 0.30), 0px 1px 2px 0px rgba(19, 21, 26, 0.29), 0px 4px 4px 0px rgba(19, 21, 26, 0.26), 0px 10px 6px 0px rgba(19, 21, 26, 0.15), 0px 17px 7px 0px rgba(19, 21, 26, 0.04), 0px 26px 7px 0px rgba(19, 21, 26, 0.01);
width: 192px;
padding: 8px;
z-index: 2000000010;
transform: translate(-50%, 0%);
position: fixed;
bottom: 72px;
left: 50%;
}
.notification {
display: none;
position: absolute;
top: -4px;
right: -5px;
width: 12px;
height: 10px;
}
.notification svg {
display: block;
}
#dropdown:not([data-no-notification]) .notification[data-active] {
display: block;
}
#dropdown button {
border: 0;
background: transparent;
color: white;
font-family: system-ui, sans-serif;
font-size: 14px;
white-space: nowrap;
text-decoration: none;
margin: 0;
display: flex;
align-items: center;
width: 100%;
padding: 8px;
border-radius: 8px;
}
#dropdown button:hover, #dropdown button:focus-visible {
background: #FFFFFF20;
cursor: pointer;
}
#dropdown button.active {
background: rgba(71, 78, 94, 1);
}
#dropdown .icon {
position: relative;
height: 20px;
width: 20px;
padding: 1px;
margin-right: 0.5em;
}
#dropdown .icon svg {
max-height: 100%;
max-width: 100%;
}
`;
canvas.append(style);
const dropdown = document.createElement("div");
dropdown.id = "dropdown";
dropdown.toggleAttribute("data-no-notification", settings.config.disableAppNotification);
for (const app of hiddenApps) {
const buttonContainer = document.createElement("div");
buttonContainer.classList.add("item");
const button = document.createElement("button");
button.setAttribute("data-app-id", app.id);
const iconContainer = document.createElement("div");
const iconElement = document.createElement("template");
iconElement.innerHTML = app.icon ? getAppIcon(app.icon) : "?";
iconContainer.append(iconElement.content.cloneNode(true));
const notification = document.createElement("div");
notification.classList.add("notification");
iconContainer.append(notification);
iconContainer.classList.add("icon");
button.append(iconContainer);
button.append(document.createTextNode(app.name));
button.addEventListener("click", () => {
overlay.toggleAppStatus(app);
});
buttonContainer.append(button);
dropdown.append(buttonContainer);
app.eventTarget.addEventListener("toggle-notification", (evt) => {
if (!(evt instanceof CustomEvent)) return;
let newState = evt.detail.state ?? true;
let level = notificationLevels.includes(evt?.detail?.level) ? evt.detail.level : "error";
notification.toggleAttribute("data-active", newState);
if (newState) {
notification.setAttribute("data-level", level);
notification.innerHTML = notificationSVGs[level];
}
app.notification.state = newState;
if (newState) app.notification.level = level;
eventTarget.dispatchEvent(
new CustomEvent("toggle-notification", {
detail: {
state: hiddenApps.some((p) => p.notification.state === true),
level: ["error", "warning", "info"].find(
(notificationLevel) => hiddenApps.some(
(p) => p.notification.state === true && p.notification.level === notificationLevel
)
) ?? "error"
}
})
);
});
}
canvas.append(dropdown);
}
}
};
const apps = [
...[astroDevToolApp, astroXrayApp, astroAuditApp, astroSettingsApp, astroMoreApp].map(
(appDef) => prepareApp(appDef, true)
),
...customAppsDefinitions.map((appDef) => prepareApp(appDef, false))
];
overlay.apps = apps;
document.body.append(overlay);
document.addEventListener("astro:after-swap", () => {
document.body.append(overlay);
});
});