getfilepress 0.1.1 → 0.1.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/README.md CHANGED
@@ -84,6 +84,15 @@ export default defineFilepressConfig({
84
84
  author: 'Me',
85
85
  postsPerPage: 10,
86
86
  topics: [{ label: 'Essays', tag: 'essays' }],
87
+ nav: [
88
+ { label: 'Posts', href: '/' },
89
+ { label: 'GitHub', href: 'https://github.com/acme/site', icon: 'github' }
90
+ ],
91
+ // Replaces the default RSS + Topics row when set.
92
+ footerLinks: [
93
+ { label: 'RSS', href: '/rss.xml' },
94
+ { label: 'GitHub', href: 'https://github.com/acme/site', icon: 'github' }
95
+ ],
87
96
  newsletter: {
88
97
  url: 'https://buttondown.email/me',
89
98
  blurb: 'Occasional notes.',
@@ -92,7 +101,7 @@ export default defineFilepressConfig({
92
101
  });
93
102
  ```
94
103
 
95
- `title` and `url` are required; missing values fail the build with a clear error.
104
+ `title` and `url` are required; missing values fail the build with a clear error. Nav/footer items may set `icon: 'github'` for a built-in mark.
96
105
 
97
106
  ## Theming
98
107
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "getfilepress",
3
- "version": "0.1.1",
3
+ "version": "0.1.2",
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`.",
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@filepress/app",
3
3
  "private": true,
4
- "version": "0.1.1",
4
+ "version": "0.1.2",
5
5
  "type": "module",
6
6
  "description": "The single SvelteKit app for filepress. Sites under sites/* supply config + posts + static; this package owns all routes.",
7
7
  "scripts": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@filepress/core",
3
- "version": "0.1.1",
3
+ "version": "0.1.2",
4
4
  "private": true,
5
5
  "type": "module",
6
6
  "description": "Reusable engine for filepress sites: content loader, Markdown pipeline, feed/sitemap builders, config helper, Essay theme, and shared Svelte components.",
@@ -0,0 +1,19 @@
1
+ <script lang="ts">
2
+ import type { NavIconName } from '../config';
3
+
4
+ let { name }: { name: NavIconName } = $props();
5
+ </script>
6
+
7
+ {#if name === 'github'}
8
+ <svg class="nav-icon" viewBox="0 0 16 16" width="16" height="16" aria-hidden="true" focusable="false">
9
+ <path
10
+ fill="currentColor"
11
+ d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38
12
+ 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01
13
+ 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95
14
+ 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27s1.36.09 2 .27c1.53-1.04
15
+ 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48
16
+ 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.01 8.01 0 0 0 16 8c0-4.42-3.58-8-8-8z"
17
+ />
18
+ </svg>
19
+ {/if}
@@ -1,5 +1,6 @@
1
1
  <script lang="ts">
2
2
  import type { SiteConfig } from '../config';
3
+ import NavIcon from './NavIcon.svelte';
3
4
 
4
5
  let { site, year = new Date().getFullYear() }: { site: SiteConfig; year?: number } = $props();
5
6
  </script>
@@ -8,8 +9,21 @@
8
9
  <div class="wrap">
9
10
  <span>&copy; {year} {site.author}</span>
10
11
  <span class="footer-links">
11
- <a href="/rss.xml">RSS</a>
12
- <a href="/topics">Topics</a>
12
+ {#each site.footerLinks as item (item.href)}
13
+ <a
14
+ href={item.href}
15
+ class:has-icon={Boolean(item.icon)}
16
+ class:nav-github={item.icon === 'github'}
17
+ {...(item.icon === 'github'
18
+ ? { target: '_blank', rel: 'noopener noreferrer' }
19
+ : {})}
20
+ >
21
+ {#if item.icon}
22
+ <NavIcon name={item.icon} />
23
+ {/if}
24
+ <span class="nav-label">{item.label}</span>
25
+ </a>
26
+ {/each}
13
27
  </span>
14
28
  </div>
15
29
  </footer>
@@ -1,5 +1,6 @@
1
1
  <script lang="ts">
2
2
  import type { SiteConfig } from '../config';
3
+ import NavIcon from './NavIcon.svelte';
3
4
 
4
5
  let { site }: { site: SiteConfig } = $props();
5
6
  </script>
@@ -21,7 +22,19 @@
21
22
  </div>
22
23
  <nav class="site-nav" aria-label="Primary">
23
24
  {#each site.nav as item (item.href)}
24
- <a href={item.href}>{item.label}</a>
25
+ <a
26
+ href={item.href}
27
+ class:has-icon={Boolean(item.icon)}
28
+ class:nav-github={item.icon === 'github'}
29
+ {...(item.icon === 'github'
30
+ ? { target: '_blank', rel: 'noopener noreferrer' }
31
+ : {})}
32
+ >
33
+ {#if item.icon}
34
+ <NavIcon name={item.icon} />
35
+ {/if}
36
+ <span class="nav-label">{item.label}</span>
37
+ </a>
25
38
  {/each}
26
39
  </nav>
27
40
  </div>
@@ -22,9 +22,14 @@ export interface Topic {
22
22
  tag: string;
23
23
  }
24
24
 
25
+ /** Built-in icons that chrome can render beside a nav/footer label. */
26
+ export type NavIconName = 'github';
27
+
25
28
  export interface NavItem {
26
29
  label: string;
27
30
  href: string;
31
+ /** Optional icon rendered with the label (e.g. GitHub mark). */
32
+ icon?: NavIconName;
28
33
  }
29
34
 
30
35
  /** Fully-resolved site configuration (after defaults are applied). */
@@ -52,6 +57,11 @@ export interface SiteConfig {
52
57
  */
53
58
  homePage: string | null;
54
59
  nav: NavItem[];
60
+ /**
61
+ * Footer link row. Defaults to RSS + Topics when omitted.
62
+ * Pass an explicit list (including RSS/Topics if you still want them) to customize.
63
+ */
64
+ footerLinks: NavItem[];
55
65
  topics: Topic[];
56
66
  newsletter: NewsletterConfig | null;
57
67
  }
@@ -71,10 +81,33 @@ export interface SiteConfigInput {
71
81
  /** Static page slug to show at `/` (post index then lives at `/writing`). */
72
82
  homePage?: string;
73
83
  nav?: NavItem[];
84
+ /** Custom footer links; replaces the default RSS + Topics row when set. */
85
+ footerLinks?: NavItem[];
74
86
  topics?: Topic[];
75
87
  newsletter?: NewsletterConfig | null;
76
88
  }
77
89
 
90
+ const defaultFooterLinks: NavItem[] = [
91
+ { label: 'RSS', href: '/rss.xml' },
92
+ { label: 'Topics', href: '/topics' }
93
+ ];
94
+
95
+ function normalizeNavItems(items: NavItem[] | undefined): NavItem[] | null {
96
+ if (!items?.length) return null;
97
+ return items.map((item) => {
98
+ const label = (item.label ?? '').trim();
99
+ const href = (item.href ?? '').trim();
100
+ if (!label || !href) {
101
+ throw new Error('filepress.config: nav/footerLinks entries need non-empty label and href.');
102
+ }
103
+ const icon = item.icon;
104
+ if (icon != null && icon !== 'github') {
105
+ throw new Error(`filepress.config: unsupported icon "${String(icon)}" (supported: github).`);
106
+ }
107
+ return icon ? { label, href, icon } : { label, href };
108
+ });
109
+ }
110
+
78
111
  /** Path to page 1 of the chronological post index. */
79
112
  export function postsIndexPath(site: Pick<SiteConfig, 'homePage'>): string {
80
113
  return site.homePage ? '/writing' : '/';
@@ -131,7 +164,8 @@ export function defineFilepressConfig(input: SiteConfigInput): SiteConfig {
131
164
  ? Math.floor(input.postsPerPage as number)
132
165
  : 10,
133
166
  homePage,
134
- nav: input.nav && input.nav.length ? input.nav : defaultNav,
167
+ nav: normalizeNavItems(input.nav) ?? defaultNav,
168
+ footerLinks: normalizeNavItems(input.footerLinks) ?? [...defaultFooterLinks],
135
169
  topics: input.topics ?? [],
136
170
  newsletter: input.newsletter ?? null
137
171
  };
@@ -19,7 +19,8 @@ export type {
19
19
  SiteConfigInput,
20
20
  NewsletterConfig,
21
21
  Topic,
22
- NavItem
22
+ NavItem,
23
+ NavIconName
23
24
  } from './config';
24
25
 
25
26
  export { formatDate } from './format';
@@ -177,6 +177,24 @@ body {
177
177
  color: var(--accent);
178
178
  }
179
179
 
180
+ .site-nav a.has-icon,
181
+ .site-footer a.has-icon {
182
+ display: inline-flex;
183
+ align-items: center;
184
+ gap: 0.4em;
185
+ }
186
+
187
+ .site-nav .nav-icon,
188
+ .site-footer .nav-icon {
189
+ display: block;
190
+ flex-shrink: 0;
191
+ }
192
+
193
+ .site-nav a.nav-github {
194
+ text-transform: none;
195
+ letter-spacing: 0.06em;
196
+ }
197
+
180
198
  .site-footer {
181
199
  border-top: 1px solid var(--rule);
182
200
  margin-top: clamp(2.5rem, 6vw, 4rem);
@@ -195,6 +213,7 @@ body {
195
213
 
196
214
  .site-footer .footer-links {
197
215
  display: flex;
216
+ align-items: center;
198
217
  gap: 1.1rem;
199
218
  }
200
219
 
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@filepress/import",
3
- "version": "0.1.1",
3
+ "version": "0.1.2",
4
4
  "private": true,
5
5
  "type": "module",
6
6
  "description": "Crawl an existing site and scaffold a filepress content-only sibling (optional Ollama restyle).",