astro-integration-pocketbase 1.4.1 → 1.4.2-next.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "astro-integration-pocketbase",
3
- "version": "1.4.1",
3
+ "version": "1.4.2-next.2",
4
4
  "description": "An Astro integration to support developers working with astro-loader-pocketbase.",
5
5
  "keywords": [
6
6
  "astro",
@@ -13,6 +13,13 @@
13
13
  "tooling"
14
14
  ],
15
15
  "homepage": "https://github.com/pawcoding/astro-integration-pocketbase",
16
+ "bugs": {
17
+ "url": "https://github.com/pawcoding/astro-integration-pocketbase/issues"
18
+ },
19
+ "repository": {
20
+ "type": "git",
21
+ "url": "git+https://github.com/pawcoding/astro-integration-pocketbase.git"
22
+ },
16
23
  "license": "MIT",
17
24
  "author": "Luis Wolf <development@pawcode.de> (https://pawcode.de)",
18
25
  "type": "module",
@@ -31,26 +38,30 @@
31
38
  "prepare": "husky"
32
39
  },
33
40
  "devDependencies": {
34
- "@commitlint/cli": "^19.7.1",
35
- "@commitlint/config-conventional": "^19.7.1",
36
- "@eslint/js": "^9.20.0",
37
- "@stylistic/eslint-plugin": "^3.1.0",
38
- "@types/node": "^22.13.4",
39
- "astro": "^5.3.0",
40
- "eslint": "^9.20.1",
41
- "eslint-config-prettier": "^10.0.1",
42
- "eventsource": "^3.0.5",
43
- "globals": "^15.15.0",
41
+ "@commitlint/cli": "^19.8.0",
42
+ "@commitlint/config-conventional": "^19.8.0",
43
+ "@eslint/js": "^9.23.0",
44
+ "@stylistic/eslint-plugin": "^4.2.0",
45
+ "@types/node": "^22.13.14",
46
+ "astro": "^5.5.5",
47
+ "eslint": "^9.23.0",
48
+ "eslint-config-prettier": "^10.1.1",
49
+ "eventsource": "^3.0.6",
50
+ "globals": "^16.0.0",
44
51
  "husky": "^9.1.7",
45
- "lint-staged": "^15.4.3",
46
- "prettier": "^3.5.1",
52
+ "lint-staged": "^15.5.0",
53
+ "prettier": "^3.5.3",
47
54
  "prettier-plugin-organize-imports": "^4.1.0",
48
- "prettier-plugin-packagejson": "^2.5.8",
49
- "typescript": "^5.7.3",
50
- "typescript-eslint": "^8.24.0"
55
+ "prettier-plugin-packagejson": "^2.5.10",
56
+ "typescript": "^5.8.2",
57
+ "typescript-eslint": "^8.28.0"
51
58
  },
52
59
  "peerDependencies": {
53
60
  "astro": "^5.0.0",
54
61
  "eventsource": "^3.0.0"
62
+ },
63
+ "publishConfig": {
64
+ "access": "public",
65
+ "provenance": true
55
66
  }
56
67
  }
@@ -7,6 +7,12 @@ export const onRequest = defineMiddleware(async (context, next) => {
7
7
  const entities = findEntitiesRecursive(props).map((entity) => entity.data);
8
8
 
9
9
  const response = await next();
10
+ const contentType = response.headers.get("content-type");
11
+ if (!contentType?.includes("text/html")) {
12
+ // Pass through non-HTML responses unchanged
13
+ return response;
14
+ }
15
+
10
16
  const body = await response.text();
11
17
 
12
18
  // Append the entities to the <head>
@@ -1,41 +1,53 @@
1
- import type { DevToolbarCard } from "astro/runtime/client/dev-toolbar/ui-library/card.js";
2
1
  import type { Entity } from "../types/entity";
3
2
 
4
3
  /**
5
- * Creates a card for an entity.
4
+ * Creates cards for the entities.
6
5
  */
7
- export function createEntity(data: Entity, baseUrl?: string): DevToolbarCard {
8
- // Create the main card
9
- const main = document.createElement("astro-dev-toolbar-card");
6
+ export function createEntities(data: Array<Entity>, baseUrl: string): string {
7
+ return /* HTML */ `
8
+ <style>
9
+ .entity {
10
+ position: relative;
10
11
 
11
- // Create the main content container
12
- const content = document.createElement("div");
13
- content.style.position = "relative";
14
- main.appendChild(content);
12
+ pre {
13
+ margin: 0;
14
+ overflow: auto;
15
+ }
15
16
 
16
- // Add the "View in PocketBase" button
17
- if (baseUrl) {
18
- const url = `${baseUrl}/_/#/collections?collection=${data.collectionId}&recordId=${data.id}`;
17
+ astro-dev-toolbar-button {
18
+ position: absolute;
19
+ top: 0;
20
+ right: 0;
21
+ }
22
+ }
23
+ </style>
19
24
 
20
- const viewInPocketbase = document.createElement("astro-dev-toolbar-button");
21
- viewInPocketbase.size = "small";
22
- viewInPocketbase.buttonStyle = "purple";
23
- viewInPocketbase.textContent = "View in PocketBase";
24
- viewInPocketbase.style.position = "absolute";
25
- viewInPocketbase.style.top = "0";
26
- viewInPocketbase.style.right = "0";
27
- viewInPocketbase.addEventListener("click", () => {
28
- window.open(url, "_blank");
29
- });
30
- content.appendChild(viewInPocketbase);
31
- }
25
+ ${data.map((entity) => createEntity(entity, baseUrl)).join("")}
26
+ `;
27
+ }
32
28
 
33
- // Add the entity data
34
- const entity = document.createElement("pre");
35
- entity.style.margin = "0";
36
- entity.style.overflow = "auto";
37
- entity.textContent = JSON.stringify(data, null, 2);
38
- content.appendChild(entity);
29
+ /**
30
+ * Creates a card for a single entity
31
+ */
32
+ function createEntity(data: Entity, baseUrl: string): string {
33
+ return /* HTML */ `
34
+ <astro-dev-toolbar-card>
35
+ <div class="entity">
36
+ <pre>${JSON.stringify(data, null, 2).replaceAll(/</g, "&lt;")}</pre>
39
37
 
40
- return main;
38
+ ${baseUrl
39
+ ? /* HTML */ `
40
+ <astro-dev-toolbar-button
41
+ size="small"
42
+ button-style="purple"
43
+ title="View in PocketBase"
44
+ onclick="window.open('${baseUrl}/_/#/collections?collection=${data.collectionId}&recordId=${data.id}', '_blank')"
45
+ >
46
+ View in PocketBase
47
+ </astro-dev-toolbar-button>
48
+ `
49
+ : ""}
50
+ </div>
51
+ </astro-dev-toolbar-card>
52
+ `;
41
53
  }
@@ -1,98 +1,155 @@
1
1
  import type { ToolbarServerHelpers } from "astro";
2
2
  import type { DevToolbarButton } from "astro/runtime/client/dev-toolbar/ui-library/button.js";
3
+ import type { DevToolbarWindow } from "astro/runtime/client/dev-toolbar/ui-library/window.js";
3
4
  import { default as packageJson } from "../../../package.json";
4
-
5
- export interface HeaderElements {
6
- header: HTMLElement;
7
- refresh: DevToolbarButton;
8
- toggleContainer: HTMLDivElement;
9
- }
5
+ import type { ToolbarOptions } from "../types/options";
10
6
 
11
7
  /**
12
8
  * Creates the header for the PocketBase toolbar.
13
9
  */
14
- export function createHeader(server: ToolbarServerHelpers): HeaderElements {
15
- // Create the header
16
- const header = document.createElement("header");
17
- header.style.display = "grid";
18
- header.style.gap = "0.25rem";
19
- header.style.gridTemplateColumns = "auto auto 1fr";
10
+ export function createHeader(
11
+ windowElement: DevToolbarWindow,
12
+ server: ToolbarServerHelpers,
13
+ { hasContentLoader, realtime }: ToolbarOptions
14
+ ): void {
15
+ const header = windowElement.querySelector("header");
16
+ if (!header) {
17
+ throw new Error("The header element is missing");
18
+ }
19
+
20
+ header.innerHTML = /* HTML */ `
21
+ <style>
22
+ header {
23
+ display: grid;
24
+ grid-template-columns: auto auto 1fr;
25
+ gap: 0.5rem;
26
+ }
27
+
28
+ h1 {
29
+ display: flex;
30
+ align-items: center;
31
+ gap: 8px;
32
+ font-weight: 600;
33
+ color: #fff;
34
+ margin: 0;
35
+ font-size: 22px;
36
+ }
20
37
 
21
- // Create the title
22
- const title = document.createElement("h3");
23
- title.style.marginTop = "0.25rem";
24
- title.textContent = "PocketBase";
25
- header.appendChild(title);
38
+ .actions {
39
+ display: flex;
40
+ align-items: start;
41
+ justify-content: flex-end;
42
+ gap: 0.25rem;
26
43
 
27
- // Create the version badge
28
- const version = document.createElement("astro-dev-toolbar-badge");
29
- version.textContent = packageJson.version;
30
- version.badgeStyle = "yellow";
31
- header.appendChild(version);
44
+ .toggle-container {
45
+ display: flex;
46
+ align-items: center;
32
47
 
33
- // Create the actions container
34
- const actions = document.createElement("div");
35
- actions.style.display = "flex";
36
- actions.style.alignItems = "start";
37
- actions.style.justifyContent = "flex-end";
38
- actions.style.gap = "0.25rem";
39
- header.appendChild(actions);
48
+ label {
49
+ font-size: 0.8rem;
50
+ }
51
+ }
52
+ }
53
+ </style>
40
54
 
41
- // Create the real-time toggle
42
- const toggleContainer = document.createElement("div");
43
- toggleContainer.style.alignItems = "center";
44
- // The toggle container is hidden by default
45
- toggleContainer.style.display = "none";
46
- actions.appendChild(toggleContainer);
55
+ <h1>PocketBase</h1>
56
+ <astro-dev-toolbar-badge badge-style="yellow">
57
+ ${packageJson.version}
58
+ </astro-dev-toolbar-badge>
47
59
 
48
- const toggleLabel = document.createElement("label");
49
- toggleLabel.textContent = "Real-time updates";
50
- toggleLabel.htmlFor = "real-time-toggle";
51
- toggleLabel.title = "Enable or disable real-time updates temporarily";
52
- toggleLabel.style.fontSize = "0.8rem";
53
- toggleContainer.appendChild(toggleLabel);
60
+ <div class="actions">
61
+ ${realtime
62
+ ? /* HTML */ `
63
+ <div class="toggle-container">
64
+ <label
65
+ for="real-time"
66
+ title="Enable or disable real-time updates temporarily"
67
+ >
68
+ Real-time updates
69
+ </label>
70
+ <!-- real-time-toggle -->
71
+ </div>
72
+ `
73
+ : ""}
74
+ ${hasContentLoader
75
+ ? /* HTML */ `
76
+ <astro-dev-toolbar-button
77
+ id="refresh-content"
78
+ size="small"
79
+ button-style="green"
80
+ title="Right click to force refresh every collection"
81
+ >
82
+ Refresh content
83
+ </astro-dev-toolbar-button>
84
+ `
85
+ : ""}
86
+ </div>
87
+ `;
54
88
 
55
- const toggle = document.createElement("astro-dev-toolbar-toggle");
56
- toggle.input.id = "real-time-toggle";
57
- toggle.input.title = "Enable or disable real-time updates temporarily";
58
- // Set the toggle state based on the local storage, default to true
59
- toggle.input.checked = !(
60
- localStorage.getItem("astro-integration-pocketbase:real-time") === "false"
61
- );
62
- toggle.input.addEventListener("change", () => {
63
- // Store the toggle state in the local storage
64
- localStorage.setItem(
89
+ if (realtime) {
90
+ // Create the toggle for real-time updates
91
+ const realTimeToggle = document.createElement("astro-dev-toolbar-toggle");
92
+ realTimeToggle.input.id = "real-time-toggle";
93
+ realTimeToggle.input.title =
94
+ "Enable or disable real-time updates temporarily";
95
+ // Set the toggle state based on the local storage, default to true
96
+ realTimeToggle.input.checked = !(
97
+ localStorage.getItem("astro-integration-pocketbase:real-time") === "false"
98
+ );
99
+ realTimeToggle.input.addEventListener("change", () => {
100
+ // Store the toggle state in the local storage
101
+ localStorage.setItem(
102
+ "astro-integration-pocketbase:real-time",
103
+ realTimeToggle.input.checked.toString()
104
+ );
105
+
106
+ // Send the toggle state to the server
107
+ server.send(
108
+ "astro-integration-pocketbase:real-time",
109
+ realTimeToggle.input.checked
110
+ );
111
+ });
112
+ // Send the initial toggle state to the server
113
+ server.send(
65
114
  "astro-integration-pocketbase:real-time",
66
- toggle.input.checked.toString()
115
+ realTimeToggle.input.checked
67
116
  );
117
+ windowElement
118
+ .querySelector(".toggle-container")
119
+ ?.appendChild(realTimeToggle);
120
+ }
68
121
 
69
- // Send the toggle state to the server
70
- server.send("astro-integration-pocketbase:real-time", toggle.input.checked);
71
- });
72
- // Send the initial toggle state to the server
73
- server.send("astro-integration-pocketbase:real-time", toggle.input.checked);
74
- toggleContainer.appendChild(toggle);
122
+ if (hasContentLoader) {
123
+ // Add click listeners to the refresh button
124
+ const refresh = windowElement.querySelector(
125
+ "#refresh-content"
126
+ ) as DevToolbarButton | null;
127
+ if (!refresh) {
128
+ throw new Error("The refresh button is missing");
129
+ }
75
130
 
76
- // Create the refresh button
77
- const refresh = document.createElement("astro-dev-toolbar-button");
78
- refresh.size = "small";
79
- refresh.buttonStyle = "green";
80
- refresh.textContent = "Refresh content";
81
- refresh.title = "Right click to force refresh every collection";
82
- // The refresh button is hidden by default
83
- refresh.style.display = "none";
84
- refresh.addEventListener("click", () => {
85
- server.send("astro-integration-pocketbase:refresh", { force: false });
86
- });
87
- refresh.addEventListener("contextmenu", (event) => {
88
- event.preventDefault();
89
- server.send("astro-integration-pocketbase:refresh", { force: true });
90
- });
91
- actions.appendChild(refresh);
131
+ refresh.addEventListener("click", () => {
132
+ server.send("astro-integration-pocketbase:refresh", { force: false });
133
+ });
134
+ refresh.addEventListener("contextmenu", (event) => {
135
+ event.preventDefault();
136
+ server.send("astro-integration-pocketbase:refresh", { force: true });
137
+ });
92
138
 
93
- return {
94
- header,
95
- refresh,
96
- toggleContainer
97
- };
139
+ server.on(
140
+ "astro-integration-pocketbase:refresh",
141
+ ({ loading }: { loading?: boolean }) => {
142
+ // Show loading state while refreshing content
143
+ if (loading) {
144
+ refresh.textContent = "Refreshing content...";
145
+ refresh.buttonStyle = "gray";
146
+ refresh.style.pointerEvents = "none";
147
+ } else {
148
+ refresh.textContent = "Refresh content";
149
+ refresh.buttonStyle = "green";
150
+ refresh.style.pointerEvents = "unset";
151
+ }
152
+ }
153
+ );
154
+ }
98
155
  }
@@ -1,23 +1,20 @@
1
- import type { DevToolbarCard } from "astro/runtime/client/dev-toolbar/ui-library/card.js";
2
-
3
1
  /**
4
2
  * Creates a placeholder card.
5
3
  */
6
- export function createPlaceholder(): DevToolbarCard {
7
- // Create the main card
8
- const main = document.createElement("astro-dev-toolbar-card");
9
-
10
- // Create the main content container
11
- const content = document.createElement("div");
12
- content.style.display = "flex";
13
- content.style.alignItems = "center";
14
- content.style.justifyContent = "center";
15
- main.appendChild(content);
16
-
17
- // Add the placeholder text
18
- const placeholder = document.createElement("span");
19
- placeholder.textContent = "Here you will see the raw content of an entity";
20
- content.appendChild(placeholder);
4
+ export function createPlaceholder(): string {
5
+ return /* HTML */ `
6
+ <style>
7
+ #placeholder div {
8
+ display: flex;
9
+ align-items: center;
10
+ justify-content: center;
11
+ }
12
+ </style>
21
13
 
22
- return main;
14
+ <astro-dev-toolbar-card id="placeholder">
15
+ <div>
16
+ <span> Here you will see the raw content of an entity </span>
17
+ </div>
18
+ </astro-dev-toolbar-card>
19
+ `;
23
20
  }
@@ -1,9 +1,13 @@
1
+ import {
2
+ closeOnOutsideClick,
3
+ createWindowElement,
4
+ synchronizePlacementOnUpdate
5
+ } from "astro/runtime/client/dev-toolbar/apps/utils/window.js";
1
6
  import type {
2
7
  ToolbarAppEventTarget,
3
8
  ToolbarServerHelpers
4
9
  } from "astro/runtime/client/dev-toolbar/helpers.js";
5
- import { createEntity, createHeader, createPlaceholder } from "./dom/";
6
- import { listenToNavigation } from "./page-navigation-listener";
10
+ import { createEntities, createHeader, createPlaceholder } from "./dom";
7
11
  import type { Entity } from "./types/entity";
8
12
  import type { ToolbarOptions } from "./types/options";
9
13
 
@@ -16,137 +20,79 @@ declare global {
16
20
  /**
17
21
  * Initializes the PocketBase toolbar.
18
22
  */
19
- export async function initToolbar(
23
+ export function initToolbar(
20
24
  canvas: ShadowRoot,
21
25
  app: ToolbarAppEventTarget,
22
26
  server: ToolbarServerHelpers
23
- ): Promise<void> {
24
- // Base url of the PocketBase instance
25
- let pbUrl: string | undefined = undefined;
26
-
27
- const container = document.createElement("astro-dev-toolbar-window");
28
-
29
- const { header, refresh, toggleContainer } = createHeader(server);
30
- container.appendChild(header);
31
-
32
- // Container for the main content
33
- const contentContainer = document.createElement("div");
34
- contentContainer.style.display = "flex";
35
- contentContainer.style.flexDirection = "column";
36
- contentContainer.style.gap = "8px";
37
- contentContainer.style.maxHeight = "400px";
38
- contentContainer.style.overflowY = "auto";
39
- container.appendChild(contentContainer);
40
-
41
- const placeholder = createPlaceholder();
42
- contentContainer.appendChild(placeholder);
43
-
44
- app.onToggled(({ state }) => {
45
- // Clear the container
46
- contentContainer.innerHTML = "";
47
-
48
- if (!state) {
49
- // Clear the dev-window
50
- canvas.innerHTML = "";
51
- return;
27
+ ): void {
28
+ // Options for the toolbar
29
+ let options: ToolbarOptions = {
30
+ realtime: false,
31
+ hasContentLoader: false,
32
+ baseUrl: ""
33
+ };
34
+
35
+ // Update the options and refresh the toolbar
36
+ server.on(
37
+ "astro-integration-pocketbase:settings",
38
+ (updatedOptions: ToolbarOptions) => {
39
+ options = updatedOptions;
40
+ createPocketBaseWindow();
52
41
  }
42
+ );
53
43
 
54
- // Append the dev-window
55
- canvas.appendChild(container);
44
+ // Create the window (for every page navigation)
45
+ createPocketBaseWindow();
46
+ document.addEventListener("astro:after-swap", createPocketBaseWindow);
56
47
 
57
- // Check if entities are present
58
- const entities = window.__astro_entities__;
59
- if (!entities || entities.length === 0) {
60
- // No entities to display, show a placeholder
61
- contentContainer.appendChild(createPlaceholder());
62
- return;
63
- }
48
+ // Setup the window
49
+ closeOnOutsideClick(app);
50
+ synchronizePlacementOnUpdate(app, canvas);
64
51
 
65
- // Display the information about the entities
66
- for (const entity of entities) {
67
- contentContainer.appendChild(createEntity(entity, pbUrl));
68
- }
69
- });
52
+ function createPocketBaseWindow(): void {
53
+ // Clear any existing content
54
+ canvas.innerHTML = "";
70
55
 
71
- // Update the toolbar placement based on the user's preference
72
- function updateToolbarPlacement(
73
- placement: "bottom-left" | "bottom-right" | "bottom-center"
74
- ): void {
75
- if (placement === "bottom-left") {
76
- container.style.left = "16px";
77
- container.style.right = "unset";
78
- container.style.transform = "translateX(0)";
79
- } else if (placement === "bottom-right") {
80
- container.style.left = "unset";
81
- container.style.right = "16px";
82
- container.style.transform = "translateX(0)";
83
- } else {
84
- container.style.left = "50%";
85
- container.style.right = "unset";
86
- container.style.transform = "translateX(-50%)";
87
- }
88
- }
56
+ const entities = window.__astro_entities__ || [];
89
57
 
90
- // Read the initial toolbar placement from local storage
91
- // This is a workaround since the initial toolbar placement is not available via any API
92
- const settings = localStorage.getItem("astro:dev-toolbar:settings");
93
- if (settings) {
94
- const { placement } = JSON.parse(settings);
95
- updateToolbarPlacement(placement);
96
- }
58
+ // Create the main window element
59
+ const windowElement = createWindowElement(/* HTML */ `
60
+ <style>
61
+ :host astro-dev-toolbar-window {
62
+ max-height: 480px;
63
+ }
97
64
 
98
- // Listen for toolbar placement updates
99
- app.onToolbarPlacementUpdated(({ placement }) => {
100
- updateToolbarPlacement(placement);
101
- });
65
+ main {
66
+ display: flex;
67
+ flex-direction: column;
68
+ gap: 1rem;
69
+ overflow-y: auto;
70
+ }
71
+ </style>
102
72
 
103
- server.on(
104
- "astro-integration-pocketbase:settings",
105
- ({ hasContentLoader, realtime, baseUrl }: ToolbarOptions) => {
106
- // Show the refresh button if a loader is available
107
- if (hasContentLoader) {
108
- refresh.style.display = "unset";
109
- }
73
+ <header></header>
110
74
 
111
- // Show the real-time toggle if real-time updates are available
112
- if (realtime) {
113
- toggleContainer.style.display = "flex";
114
- }
75
+ <hr />
115
76
 
116
- // Store the base URL for later use
117
- pbUrl = baseUrl;
118
- }
119
- );
77
+ <main>
78
+ ${entities.length > 0
79
+ ? createEntities(entities, options.baseUrl)
80
+ : createPlaceholder()}
81
+ </main>
82
+ `);
120
83
 
121
- server.on(
122
- "astro-integration-pocketbase:refresh",
123
- ({ loading }: { loading?: boolean }) => {
124
- // Show loading state while refreshing content
125
- if (loading) {
126
- refresh.textContent = "Refreshing content...";
127
- refresh.buttonStyle = "gray";
128
- refresh.style.pointerEvents = "none";
129
- } else {
130
- refresh.textContent = "Refresh content";
131
- refresh.buttonStyle = "green";
132
- refresh.style.pointerEvents = "unset";
133
- }
134
- }
135
- );
84
+ // Create and insert the header
85
+ createHeader(windowElement, server, options);
136
86
 
137
- // Toggle the notification based on the presence of entities
138
- listenToNavigation(() => {
139
- // Check if entities are present
140
- const entities = window.__astro_entities__;
141
- if (!entities || entities.length === 0) {
142
- app.toggleNotification({ state: false });
87
+ // Add the window to the canvas
88
+ canvas.append(windowElement);
143
89
 
144
- // Hide the toolbar if no entities are present
90
+ // Update the toolbar depending on the current state
91
+ if (entities.length > 0) {
92
+ app.toggleNotification({ state: true, level: "info" });
93
+ } else {
94
+ app.toggleNotification({ state: false });
145
95
  app.toggleState({ state: false });
146
- return;
147
96
  }
148
-
149
- // Show the notification
150
- app.toggleNotification({ state: true, level: "info" });
151
- });
97
+ }
152
98
  }