getfilepress 0.1.7 → 0.1.9

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/README.md CHANGED
@@ -200,6 +200,8 @@ Any other static host works the same way: publish `build/` as the web root. The
200
200
 
201
201
  Full notes (including an agent checklist): [`docs/DEPLOY.md`](docs/DEPLOY.md) · product page: [getfilepress.com/deploy](https://getfilepress.com/deploy).
202
202
 
203
+ If the site ships an agent skill, write the install page from [`docs/SKILL_PAGE.md`](docs/SKILL_PAGE.md) · [getfilepress.com/skill-page](https://getfilepress.com/skill-page).
204
+
203
205
  ## Repository layout
204
206
 
205
207
  ```
@@ -215,6 +217,12 @@ scripts/ filepress CLI and create-site scaffold
215
217
  pnpm test # engine unit tests
216
218
  ```
217
219
 
220
+ <!-- xfacts-nutrition-label -->
221
+
222
+ ## Nutrition label
223
+
224
+ - **AppFacts:** [viewer](https://appfacts.dev/v#af1.eNptkkGLGzEMhf-K0dnZoVefygZKt01KYbK9lKUotjLxxmMZWzNhCPnvxZNk9tAebX9Pen7SBUYwnzRE7AkMHHyglKkU0CBTqlc9R86UGDQUQRkKGEArfiTQELylWCq2fdndCHsCc4GAsRuwqy-7KVFrs0-iVTtSENLqG474uFu3rVZfd9sNaMhDFD87-cGOnt6rj0PGns6cT2Dgpv_uBTTsh-gCZTDwywvNzafgYwcG1m0LGo5c5H4OPLhDwEzqJ3ZU4KrBUSpgfl8ggoHPZS78XprTXDtVEWdSZ9qrDwNXfcNv9J17fVGW-8SRovyHHf1CPg8-OCXMQWF0ytGoCuWR8gLLkKPjc1wsxJGyzOkoYbXFfJqfH_wQ_cGTezi5nZTlKNVMymypFB87lXyi4CMtysAWw56yHO_iLUbsSCXOogJhoaIOnNXMVasUOPUUBa5vGspol-z-CVdDHUorKN6q-xCql9G7-tW3OjofXF2ThPaEHf3p5-ZVlmLq6_JRkSXolT2SrYlCXcTihfMEBo4iqZim6bwch_2T5b5Zo2CYiqy-cO5otdmsm4-Vvv4FzW_8rQ) · [raw](https://github.com/Catalyst-Forge-LLC/filepress/blob/main/APP_FACTS.md)
225
+
218
226
  ## License
219
227
 
220
228
  MIT — see [LICENSE](LICENSE).
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "getfilepress",
3
- "version": "0.1.7",
3
+ "version": "0.1.9",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "description": "FilePress — file-based Markdown blog engine. Link this package from a content-only site (config + posts), then run `filepress build`.",
@@ -61,6 +61,7 @@
61
61
  "dev:www": "node scripts/ensure-lease.mjs getfilepress 5180 && pnpm filepress dev --site getfilepress --host 0.0.0.0",
62
62
  "create-site": "node scripts/create-site.mjs",
63
63
  "sync-siblings": "tsx scripts/sync-sibling-sites.ts",
64
+ "siblings": "tsx scripts/siblings/server.ts",
64
65
  "import": "node scripts/filepress.mjs import",
65
66
  "prepublishOnly": "node scripts/publish-gate.mjs",
66
67
  "prepack": "node scripts/prepack.mjs",
@@ -1,14 +1,23 @@
1
1
  <script lang="ts">
2
2
  import '$lib/theme-entry';
3
3
  import criticalTheme from '$critical-theme';
4
- import { SiteHeader, SiteFooter } from '@filepress/core';
4
+ import { SiteHeader, SiteFooter, isPathMountHref } from '@filepress/core';
5
5
  import config from '$site-config';
6
6
  import GenieHost from '$lib/genie/GenieHost.svelte';
7
7
 
8
-
9
8
  let { children } = $props();
9
+
10
+ function markPathMountLink(event: PointerEvent) {
11
+ const a = (event.target as HTMLElement | null)?.closest('a[href]');
12
+ if (!a) return;
13
+ const href = a.getAttribute('href');
14
+ if (!href || !isPathMountHref(href, config.paths)) return;
15
+ a.setAttribute('data-sveltekit-reload', '');
16
+ }
10
17
  </script>
11
18
 
19
+ <svelte:window onpointerdown={markPathMountLink} />
20
+
12
21
  <svelte:head>
13
22
  {#if criticalTheme}
14
23
  {@html `<style data-filepress-critical>${criticalTheme}</style>`}
@@ -0,0 +1,12 @@
1
+ import { redirect } from '@sveltejs/kit';
2
+ import type { PageServerLoad } from './$types';
3
+ import { content } from '$lib/content.server';
4
+ import config from '$site-config';
5
+
6
+ export const load: PageServerLoad = () => {
7
+ // Without homePage, the post index stays at `/`.
8
+ if (!config.homePage) {
9
+ redirect(302, '/');
10
+ }
11
+ return content.getIndexPage(1, config.postsPerPage);
12
+ };
@@ -0,0 +1,38 @@
1
+ <script lang="ts">
2
+ import type { PageData } from './$types';
3
+ import { PostIndex, absoluteUrl, ogImageUrl, postsIndexPath } from '@filepress/core';
4
+ import config from '$site-config';
5
+
6
+ let { data }: { data: PageData } = $props();
7
+
8
+ const pageTitle = $derived(`Posts — ${config.title}`);
9
+ const canonical = $derived(absoluteUrl(config, postsIndexPath(config)));
10
+ const ogImage = $derived(ogImageUrl(config));
11
+ const description = $derived(
12
+ `Posts from ${config.title}. ${config.description}`.trim()
13
+ );
14
+ </script>
15
+
16
+ <svelte:head>
17
+ <title>{pageTitle}</title>
18
+ <meta name="description" content={description} />
19
+ <link rel="canonical" href={canonical} />
20
+ <meta property="og:type" content="website" />
21
+ <meta property="og:title" content="Posts — {config.title}" />
22
+ <meta property="og:description" content={description} />
23
+ <meta property="og:url" content={canonical} />
24
+ {#if ogImage}
25
+ <meta property="og:image" content={ogImage} />
26
+ <meta name="twitter:card" content="summary" />
27
+ <meta name="twitter:image" content={ogImage} />
28
+ {/if}
29
+ </svelte:head>
30
+
31
+ <PostIndex
32
+ site={config}
33
+ featured={data.featured}
34
+ posts={data.posts}
35
+ page={data.page}
36
+ totalPages={data.totalPages}
37
+ indexHref={postsIndexPath(config)}
38
+ />
@@ -1,12 +1,8 @@
1
1
  import { redirect } from '@sveltejs/kit';
2
2
  import type { PageServerLoad } from './$types';
3
- import { content } from '$lib/content.server';
3
+ import { postsIndexPath } from '@filepress/core';
4
4
  import config from '$site-config';
5
5
 
6
6
  export const load: PageServerLoad = () => {
7
- // Without homePage, the post index stays at `/` — keep /writing as an alias.
8
- if (!config.homePage) {
9
- redirect(302, '/');
10
- }
11
- return content.getIndexPage(1, config.postsPerPage);
7
+ redirect(308, postsIndexPath(config));
12
8
  };
@@ -1,38 +1 @@
1
- <script lang="ts">
2
- import type { PageData } from './$types';
3
- import { PostIndex, absoluteUrl, ogImageUrl, postsIndexPath } from '@filepress/core';
4
- import config from '$site-config';
5
-
6
- let { data }: { data: PageData } = $props();
7
-
8
- const pageTitle = $derived(`Posts — ${config.title}`);
9
- const canonical = $derived(absoluteUrl(config, postsIndexPath(config)));
10
- const ogImage = $derived(ogImageUrl(config));
11
- const description = $derived(
12
- `Posts from ${config.title}. ${config.description}`.trim()
13
- );
14
- </script>
15
-
16
- <svelte:head>
17
- <title>{pageTitle}</title>
18
- <meta name="description" content={description} />
19
- <link rel="canonical" href={canonical} />
20
- <meta property="og:type" content="website" />
21
- <meta property="og:title" content="Posts — {config.title}" />
22
- <meta property="og:description" content={description} />
23
- <meta property="og:url" content={canonical} />
24
- {#if ogImage}
25
- <meta property="og:image" content={ogImage} />
26
- <meta name="twitter:card" content="summary" />
27
- <meta name="twitter:image" content={ogImage} />
28
- {/if}
29
- </svelte:head>
30
-
31
- <PostIndex
32
- site={config}
33
- featured={data.featured}
34
- posts={data.posts}
35
- page={data.page}
36
- totalPages={data.totalPages}
37
- indexHref={postsIndexPath(config)}
38
- />
1
+ <p>Moved to <a href="/posts">/posts</a>.</p>
@@ -11,7 +11,7 @@
11
11
  posts,
12
12
  page = 1,
13
13
  totalPages = 1,
14
- /** Page-1 URL for the post index (`/` or `/writing`). */
14
+ /** Page-1 URL for the post index (`/` or `/posts`). */
15
15
  indexHref = '/'
16
16
  }: {
17
17
  site: SiteConfig;
@@ -1,5 +1,6 @@
1
1
  <script lang="ts">
2
2
  import type { SiteConfig } from '../config';
3
+ import { isPathMountHref } from '../paths-shared';
3
4
  import NavIcon from './NavIcon.svelte';
4
5
 
5
6
  let { site, year = new Date().getFullYear() }: { site: SiteConfig; year?: number } = $props();
@@ -16,7 +17,9 @@
16
17
  class:nav-github={item.icon === 'github'}
17
18
  {...(item.icon === 'github'
18
19
  ? { target: '_blank', rel: 'noopener noreferrer' }
19
- : {})}
20
+ : isPathMountHref(item.href, site.paths)
21
+ ? { 'data-sveltekit-reload': true }
22
+ : {})}
20
23
  >
21
24
  {#if item.icon}
22
25
  <NavIcon name={item.icon} />
@@ -1,5 +1,6 @@
1
1
  <script lang="ts">
2
2
  import type { SiteConfig } from '../config';
3
+ import { isPathMountHref } from '../paths-shared';
3
4
  import NavIcon from './NavIcon.svelte';
4
5
 
5
6
  let { site }: { site: SiteConfig } = $props();
@@ -28,7 +29,9 @@
28
29
  class:nav-github={item.icon === 'github'}
29
30
  {...(item.icon === 'github'
30
31
  ? { target: '_blank', rel: 'noopener noreferrer' }
31
- : {})}
32
+ : isPathMountHref(item.href, site.paths)
33
+ ? { 'data-sveltekit-reload': true }
34
+ : {})}
32
35
  >
33
36
  {#if item.icon}
34
37
  <NavIcon name={item.icon} />
@@ -55,7 +55,7 @@ export interface SiteConfig {
55
55
  postsPerPage: number;
56
56
  /**
57
57
  * When set, `/` renders this static page slug (`pages/<slug>.md`) and the
58
- * chronological post index moves to `/writing`.
58
+ * chronological post index moves to `/posts`.
59
59
  */
60
60
  homePage: string | null;
61
61
  nav: NavItem[];
@@ -86,7 +86,7 @@ export interface SiteConfigInput {
86
86
  ogImage?: string;
87
87
  author?: string;
88
88
  postsPerPage?: number;
89
- /** Static page slug to show at `/` (post index then lives at `/writing`). */
89
+ /** Static page slug to show at `/` (post index then lives at `/posts`). */
90
90
  homePage?: string;
91
91
  nav?: NavItem[];
92
92
  /** Custom footer links; replaces the default RSS + Topics row when set. */
@@ -120,7 +120,7 @@ function normalizeNavItems(items: NavItem[] | undefined): NavItem[] | null {
120
120
 
121
121
  /** Path to page 1 of the chronological post index. */
122
122
  export function postsIndexPath(site: Pick<SiteConfig, 'homePage'>): string {
123
- return site.homePage ? '/writing' : '/';
123
+ return site.homePage ? '/posts' : '/';
124
124
  }
125
125
 
126
126
  /**
@@ -151,7 +151,7 @@ export function defineFilepressConfig(input: SiteConfigInput): SiteConfig {
151
151
  const defaultNav: NavItem[] = homePage
152
152
  ? [
153
153
  { label: 'Home', href: '/' },
154
- { label: 'Posts', href: '/writing' },
154
+ { label: 'Posts', href: '/posts' },
155
155
  { label: 'Topics', href: '/topics' }
156
156
  ]
157
157
  : [
@@ -69,7 +69,7 @@ export function buildSitemapXml(
69
69
 
70
70
  const urls: { loc: string; lastmod?: string }[] = [
71
71
  { loc: absoluteUrl(site, '/') },
72
- ...(site.homePage ? [{ loc: absoluteUrl(site, '/writing') }] : []),
72
+ ...(site.homePage ? [{ loc: absoluteUrl(site, '/posts') }] : []),
73
73
  { loc: absoluteUrl(site, '/topics') },
74
74
  { loc: absoluteUrl(site, '/tags') },
75
75
  ...extraPages,
@@ -24,6 +24,8 @@ export type {
24
24
  PathMount
25
25
  } from './config';
26
26
 
27
+ export { isPathMountHref } from './paths-shared';
28
+
27
29
  export { formatDate } from './format';
28
30
 
29
31
  export type { PostMeta, PostSource, RenderedPost, RawFrontmatter } from './content/types';
@@ -87,3 +87,11 @@ export function normalizePathMounts(input: PathMount[] | undefined): PathMount[]
87
87
  export function pathMountReservedSlugs(mounts: PathMount[]): string[] {
88
88
  return mounts.map((m) => m.url.slice(1).split('/')[0]!).filter(Boolean);
89
89
  }
90
+
91
+ /** Same-origin href that belongs to a `paths` mount (e.g. `/docs`, `/docs/install`). */
92
+ export function isPathMountHref(href: string, mounts: PathMount[]): boolean {
93
+ const raw = href.trim();
94
+ if (!raw.startsWith('/')) return false;
95
+ const path = raw.split(/[?#]/)[0] ?? '';
96
+ return mounts.some((m) => path === m.url || path.startsWith(`${m.url}/`));
97
+ }
@@ -12,7 +12,7 @@ import { join, relative, resolve, sep } from 'node:path';
12
12
  import type { PathMount } from './paths-shared';
13
13
 
14
14
  export type { PathMount } from './paths-shared';
15
- export { normalizePathMounts, pathMountReservedSlugs } from './paths-shared';
15
+ export { normalizePathMounts, pathMountReservedSlugs, isPathMountHref } from './paths-shared';
16
16
 
17
17
  /** Absolute filesystem path for a mount's source directory. */
18
18
  export function resolvePathMountDir(siteRoot: string, mount: PathMount): string {