@scalemule/news-publication 0.0.14 → 0.0.15

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.
@@ -0,0 +1,106 @@
1
+ import { decorateNetworkUrl } from './chunk-QWK6G2UF.js';
2
+
3
+ // src/network.ts
4
+ var localPublications = [
5
+ {
6
+ slug: "bayareachronicle",
7
+ name: "Bay Area Chronicle",
8
+ url: "https://bayareachronicle.com",
9
+ area: "San Francisco Bay Area",
10
+ description: "The parent home for our local community publications."
11
+ },
12
+ {
13
+ slug: "concordchronicle",
14
+ name: "Concord Chronicle",
15
+ url: "https://concordchronicle.com",
16
+ area: "Concord",
17
+ description: "A new place for Concord\u2019s local stories, independent businesses and community voices."
18
+ },
19
+ {
20
+ slug: "walnutcreektimes",
21
+ name: "Walnut Creek Times",
22
+ url: "https://walnutcreektimes.com",
23
+ area: "Walnut Creek \xB7 Rossmoor \xB7 Saranap \xB7 Pleasant Hill",
24
+ description: "A new place for Walnut Creek\u2019s local stories, independent businesses and community voices."
25
+ },
26
+ {
27
+ slug: "lamorindapost",
28
+ name: "Lamorinda Post",
29
+ url: "https://lamorindapost.com",
30
+ area: "Orinda \xB7 Lafayette \xB7 Moraga",
31
+ description: "A new home for the neighbors, businesses and community stories of Lamorinda."
32
+ },
33
+ {
34
+ slug: "alamoweekly",
35
+ name: "Alamo Weekly",
36
+ url: "https://alamoweekly.com",
37
+ area: "Alamo",
38
+ description: "A new place for Alamo\u2019s local stories, independent businesses and community voices."
39
+ },
40
+ {
41
+ slug: "danvilletimes",
42
+ name: "Danville Times",
43
+ url: "https://danvilletimes.com",
44
+ area: "Danville",
45
+ description: "A new place for Danville\u2019s local stories, independent businesses and community voices."
46
+ },
47
+ {
48
+ slug: "sanramontimes",
49
+ name: "San Ramon Times",
50
+ url: "https://sanramontimes.com",
51
+ area: "San Ramon",
52
+ description: "A new place for San Ramon\u2019s local stories, independent businesses and community voices."
53
+ },
54
+ {
55
+ slug: "diablovalleynews",
56
+ name: "Diablo Valley News",
57
+ url: "https://diablovalleynews.com",
58
+ area: "Concord \xB7 Walnut Creek \xB7 Pleasant Hill \xB7 Alamo \xB7 Danville \xB7 San Ramon",
59
+ description: "Local stories about the people, businesses and community life of the Diablo Valley."
60
+ },
61
+ {
62
+ slug: "trivalleyweekly",
63
+ name: "Tri-Valley Weekly",
64
+ url: "https://trivalleyweekly.com",
65
+ area: "Alamo \xB7 Danville \xB7 San Ramon \xB7 Dublin \xB7 Pleasanton \xB7 Livermore",
66
+ description: "Local stories about the businesses, people and community life of the Tri-Valley."
67
+ },
68
+ {
69
+ slug: "eastbaypost",
70
+ name: "East Bay Post",
71
+ url: "https://eastbaypost.com",
72
+ area: "The East Bay",
73
+ description: "A new publication connecting the people and neighborhoods of the East Bay."
74
+ },
75
+ {
76
+ slug: "napagate",
77
+ name: "Napa Gate",
78
+ url: "https://napagate.com",
79
+ area: "Napa Valley",
80
+ description: "A new local publication for the people, places and everyday life of Napa Valley.",
81
+ listed: false
82
+ }
83
+ ];
84
+ var listedPublications = localPublications.filter(
85
+ (publication) => !("listed" in publication) || publication.listed
86
+ );
87
+ var communityPublications = listedPublications.filter(
88
+ (publication) => publication.slug !== "bayareachronicle"
89
+ );
90
+ function findPublicationBySlug(slug) {
91
+ return localPublications.find((p) => p.slug === slug);
92
+ }
93
+ function findPublicationByHost(host) {
94
+ const cleanHost = host.replace(/^https?:\/\//, "").replace(/\/.*$/, "").toLowerCase();
95
+ return localPublications.find((p) => {
96
+ const pubHost = p.url.replace(/^https?:\/\//, "").replace(/\/.*$/, "").toLowerCase();
97
+ return pubHost === cleanHost || cleanHost.startsWith(`${p.slug}.`);
98
+ });
99
+ }
100
+ function getNetworkPublicationUrl(slug) {
101
+ const pub = findPublicationBySlug(slug);
102
+ if (!pub) return null;
103
+ return decorateNetworkUrl(pub.url + "/");
104
+ }
105
+
106
+ export { communityPublications, findPublicationByHost, findPublicationBySlug, getNetworkPublicationUrl, listedPublications, localPublications };
@@ -0,0 +1,57 @@
1
+ "use client";
2
+ import { listedPublications } from './chunk-5W4EMBFY.js';
3
+ import { decorateNetworkUrl } from './chunk-QWK6G2UF.js';
4
+ import { useState, useId, useRef } from 'react';
5
+ import { jsx, jsxs } from 'react/jsx-runtime';
6
+
7
+ function LocalNetworkBar({ currentSlug, className = "", style }) {
8
+ const [open, setOpen] = useState(false);
9
+ const id = useId();
10
+ const button = useRef(null);
11
+ return /* @__PURE__ */ jsx(
12
+ "nav",
13
+ {
14
+ className: `sm-network-bar ${className}`.trim(),
15
+ style,
16
+ "aria-label": "Local publication network",
17
+ onKeyDown: (e) => {
18
+ if (e.key === "Escape" && open) {
19
+ setOpen(false);
20
+ button.current?.focus();
21
+ }
22
+ },
23
+ children: /* @__PURE__ */ jsxs("div", { className: "sm-network-inner", children: [
24
+ /* @__PURE__ */ jsx("span", { className: "sm-network-label", children: "Our local sites" }),
25
+ /* @__PURE__ */ jsxs(
26
+ "button",
27
+ {
28
+ className: "sm-network-selector",
29
+ ref: button,
30
+ "aria-expanded": open,
31
+ "aria-controls": id,
32
+ onClick: () => setOpen(!open),
33
+ type: "button",
34
+ children: [
35
+ "Our local sites ",
36
+ /* @__PURE__ */ jsx("span", { "aria-hidden": "true", children: open ? "\u2212" : "+" })
37
+ ]
38
+ }
39
+ ),
40
+ /* @__PURE__ */ jsx("ul", { id, className: `sm-network-sites ${open ? "sm-network-expanded" : ""}`, "aria-label": "All local publications", children: listedPublications.map((publication) => {
41
+ const isCurrent = publication.slug === currentSlug;
42
+ const targetUrl = isCurrent ? publication.url + "/" : decorateNetworkUrl(publication.url + "/");
43
+ return /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsx(
44
+ "a",
45
+ {
46
+ href: targetUrl,
47
+ "aria-current": isCurrent ? "true" : void 0,
48
+ children: publication.name
49
+ }
50
+ ) }, publication.slug);
51
+ }) })
52
+ ] })
53
+ }
54
+ );
55
+ }
56
+
57
+ export { LocalNetworkBar };
package/dist/index.cjs CHANGED
@@ -1551,6 +1551,158 @@ function ThemeToggle({
1551
1551
  ] });
1552
1552
  }
1553
1553
 
1554
+ // src/network.ts
1555
+ var localPublications = [
1556
+ {
1557
+ slug: "bayareachronicle",
1558
+ name: "Bay Area Chronicle",
1559
+ url: "https://bayareachronicle.com",
1560
+ area: "San Francisco Bay Area",
1561
+ description: "The parent home for our local community publications."
1562
+ },
1563
+ {
1564
+ slug: "concordchronicle",
1565
+ name: "Concord Chronicle",
1566
+ url: "https://concordchronicle.com",
1567
+ area: "Concord",
1568
+ description: "A new place for Concord\u2019s local stories, independent businesses and community voices."
1569
+ },
1570
+ {
1571
+ slug: "walnutcreektimes",
1572
+ name: "Walnut Creek Times",
1573
+ url: "https://walnutcreektimes.com",
1574
+ area: "Walnut Creek \xB7 Rossmoor \xB7 Saranap \xB7 Pleasant Hill",
1575
+ description: "A new place for Walnut Creek\u2019s local stories, independent businesses and community voices."
1576
+ },
1577
+ {
1578
+ slug: "lamorindapost",
1579
+ name: "Lamorinda Post",
1580
+ url: "https://lamorindapost.com",
1581
+ area: "Orinda \xB7 Lafayette \xB7 Moraga",
1582
+ description: "A new home for the neighbors, businesses and community stories of Lamorinda."
1583
+ },
1584
+ {
1585
+ slug: "alamoweekly",
1586
+ name: "Alamo Weekly",
1587
+ url: "https://alamoweekly.com",
1588
+ area: "Alamo",
1589
+ description: "A new place for Alamo\u2019s local stories, independent businesses and community voices."
1590
+ },
1591
+ {
1592
+ slug: "danvilletimes",
1593
+ name: "Danville Times",
1594
+ url: "https://danvilletimes.com",
1595
+ area: "Danville",
1596
+ description: "A new place for Danville\u2019s local stories, independent businesses and community voices."
1597
+ },
1598
+ {
1599
+ slug: "sanramontimes",
1600
+ name: "San Ramon Times",
1601
+ url: "https://sanramontimes.com",
1602
+ area: "San Ramon",
1603
+ description: "A new place for San Ramon\u2019s local stories, independent businesses and community voices."
1604
+ },
1605
+ {
1606
+ slug: "diablovalleynews",
1607
+ name: "Diablo Valley News",
1608
+ url: "https://diablovalleynews.com",
1609
+ area: "Concord \xB7 Walnut Creek \xB7 Pleasant Hill \xB7 Alamo \xB7 Danville \xB7 San Ramon",
1610
+ description: "Local stories about the people, businesses and community life of the Diablo Valley."
1611
+ },
1612
+ {
1613
+ slug: "trivalleyweekly",
1614
+ name: "Tri-Valley Weekly",
1615
+ url: "https://trivalleyweekly.com",
1616
+ area: "Alamo \xB7 Danville \xB7 San Ramon \xB7 Dublin \xB7 Pleasanton \xB7 Livermore",
1617
+ description: "Local stories about the businesses, people and community life of the Tri-Valley."
1618
+ },
1619
+ {
1620
+ slug: "eastbaypost",
1621
+ name: "East Bay Post",
1622
+ url: "https://eastbaypost.com",
1623
+ area: "The East Bay",
1624
+ description: "A new publication connecting the people and neighborhoods of the East Bay."
1625
+ },
1626
+ {
1627
+ slug: "napagate",
1628
+ name: "Napa Gate",
1629
+ url: "https://napagate.com",
1630
+ area: "Napa Valley",
1631
+ description: "A new local publication for the people, places and everyday life of Napa Valley.",
1632
+ listed: false
1633
+ }
1634
+ ];
1635
+ var listedPublications = localPublications.filter(
1636
+ (publication) => !("listed" in publication) || publication.listed
1637
+ );
1638
+ var communityPublications = listedPublications.filter(
1639
+ (publication) => publication.slug !== "bayareachronicle"
1640
+ );
1641
+ function findPublicationBySlug(slug) {
1642
+ return localPublications.find((p) => p.slug === slug);
1643
+ }
1644
+ function findPublicationByHost(host) {
1645
+ const cleanHost = host.replace(/^https?:\/\//, "").replace(/\/.*$/, "").toLowerCase();
1646
+ return localPublications.find((p) => {
1647
+ const pubHost = p.url.replace(/^https?:\/\//, "").replace(/\/.*$/, "").toLowerCase();
1648
+ return pubHost === cleanHost || cleanHost.startsWith(`${p.slug}.`);
1649
+ });
1650
+ }
1651
+ function getNetworkPublicationUrl(slug) {
1652
+ const pub = findPublicationBySlug(slug);
1653
+ if (!pub) return null;
1654
+ return compliance.decorateNetworkUrl(pub.url + "/");
1655
+ }
1656
+ function LocalNetworkBar({ currentSlug, className = "", style }) {
1657
+ const [open, setOpen] = react.useState(false);
1658
+ const id = react.useId();
1659
+ const button = react.useRef(null);
1660
+ return /* @__PURE__ */ jsxRuntime.jsx(
1661
+ "nav",
1662
+ {
1663
+ className: `sm-network-bar ${className}`.trim(),
1664
+ style,
1665
+ "aria-label": "Local publication network",
1666
+ onKeyDown: (e) => {
1667
+ if (e.key === "Escape" && open) {
1668
+ setOpen(false);
1669
+ button.current?.focus();
1670
+ }
1671
+ },
1672
+ children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "sm-network-inner", children: [
1673
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "sm-network-label", children: "Our local sites" }),
1674
+ /* @__PURE__ */ jsxRuntime.jsxs(
1675
+ "button",
1676
+ {
1677
+ className: "sm-network-selector",
1678
+ ref: button,
1679
+ "aria-expanded": open,
1680
+ "aria-controls": id,
1681
+ onClick: () => setOpen(!open),
1682
+ type: "button",
1683
+ children: [
1684
+ "Our local sites ",
1685
+ /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": "true", children: open ? "\u2212" : "+" })
1686
+ ]
1687
+ }
1688
+ ),
1689
+ /* @__PURE__ */ jsxRuntime.jsx("ul", { id, className: `sm-network-sites ${open ? "sm-network-expanded" : ""}`, "aria-label": "All local publications", children: listedPublications.map((publication) => {
1690
+ const isCurrent = publication.slug === currentSlug;
1691
+ const targetUrl = isCurrent ? publication.url + "/" : compliance.decorateNetworkUrl(publication.url + "/");
1692
+ return /* @__PURE__ */ jsxRuntime.jsx("li", { children: /* @__PURE__ */ jsxRuntime.jsx(
1693
+ "a",
1694
+ {
1695
+ href: targetUrl,
1696
+ "aria-current": isCurrent ? "true" : void 0,
1697
+ children: publication.name
1698
+ }
1699
+ ) }, publication.slug);
1700
+ }) })
1701
+ ] })
1702
+ }
1703
+ );
1704
+ }
1705
+
1554
1706
  Object.defineProperty(exports, "COOKIE_CONSENT_BACKUP_KEY", {
1555
1707
  enumerable: true,
1556
1708
  get: function () { return compliance.COOKIE_CONSENT_BACKUP_KEY; }
@@ -1646,6 +1798,7 @@ exports.EVENTS = EVENTS;
1646
1798
  exports.FEATURE_NAMES = FEATURE_NAMES;
1647
1799
  exports.JOB_EMPLOYMENT_TYPES = JOB_EMPLOYMENT_TYPES;
1648
1800
  exports.LAYOUT_COOKIE = LAYOUT_COOKIE;
1801
+ exports.LocalNetworkBar = LocalNetworkBar;
1649
1802
  exports.MEET_ACTIVITIES = MEET_ACTIVITIES;
1650
1803
  exports.NEWS_CACHE = NEWS_CACHE;
1651
1804
  exports.NewsError = NewsError;
@@ -1674,6 +1827,7 @@ exports.classifiedPath = classifiedPath;
1674
1827
  exports.classifiedSearchPath = classifiedSearchPath;
1675
1828
  exports.clearTheme = clearTheme;
1676
1829
  exports.clipChars = clipChars;
1830
+ exports.communityPublications = communityPublications;
1677
1831
  exports.composeEdition = composeEdition;
1678
1832
  exports.dealDollars = dealDollars;
1679
1833
  exports.dealGoPath = dealGoPath;
@@ -1688,6 +1842,9 @@ exports.featureEnabled = featureEnabled;
1688
1842
  exports.feedCacheKey = feedCacheKey;
1689
1843
  exports.feedCacheOptions = feedCacheOptions;
1690
1844
  exports.filterNews = filterNews;
1845
+ exports.findPublicationByHost = findPublicationByHost;
1846
+ exports.findPublicationBySlug = findPublicationBySlug;
1847
+ exports.getNetworkPublicationUrl = getNetworkPublicationUrl;
1691
1848
  exports.getStoredTheme = getStoredTheme;
1692
1849
  exports.getSystemTheme = getSystemTheme;
1693
1850
  exports.inventoryCacheOptions = inventoryCacheOptions;
@@ -1697,7 +1854,9 @@ exports.isEmploymentType = isEmploymentType;
1697
1854
  exports.jobEmployerBody = jobEmployerBody;
1698
1855
  exports.jobOpeningBody = jobOpeningBody;
1699
1856
  exports.jobPostingBody = jobPostingBody;
1857
+ exports.listedPublications = listedPublications;
1700
1858
  exports.llmsText = llmsText;
1859
+ exports.localPublications = localPublications;
1701
1860
  exports.matchesStoryTag = matchesStoryTag;
1702
1861
  exports.nearbyUpdates = nearbyUpdates;
1703
1862
  exports.newsArticleJsonLd = newsArticleJsonLd;
package/dist/index.d.cts CHANGED
@@ -7,6 +7,8 @@ export { COOKIE_CONSENT_BACKUP_KEY, COOKIE_CONSENT_EVENT, COOKIE_CONSENT_KEY, CO
7
7
  export { CookieConsentBanner, CookieConsentBannerProps } from './cookie-consent-banner.cjs';
8
8
  export { CookieSettingsView, CookieSettingsViewProps } from './cookie-settings-view.cjs';
9
9
  export { ThemeToggle, ThemeToggleProps } from './theme-toggle.cjs';
10
+ export { PublicationNetworkItem, communityPublications, findPublicationByHost, findPublicationBySlug, getNetworkPublicationUrl, listedPublications, localPublications } from './network.cjs';
11
+ export { LocalNetworkBar, LocalNetworkBarProps } from './network-bar.cjs';
10
12
  import 'react';
11
13
 
12
14
  /** Walnut Creek Times broadsheet colors. A paper overrides only what it changes. */
package/dist/index.d.ts CHANGED
@@ -7,6 +7,8 @@ export { COOKIE_CONSENT_BACKUP_KEY, COOKIE_CONSENT_EVENT, COOKIE_CONSENT_KEY, CO
7
7
  export { CookieConsentBanner, CookieConsentBannerProps } from './cookie-consent-banner.js';
8
8
  export { CookieSettingsView, CookieSettingsViewProps } from './cookie-settings-view.js';
9
9
  export { ThemeToggle, ThemeToggleProps } from './theme-toggle.js';
10
+ export { PublicationNetworkItem, communityPublications, findPublicationByHost, findPublicationBySlug, getNetworkPublicationUrl, listedPublications, localPublications } from './network.js';
11
+ export { LocalNetworkBar, LocalNetworkBarProps } from './network-bar.js';
10
12
  import 'react';
11
13
 
12
14
  /** Walnut Creek Times broadsheet colors. A paper overrides only what it changes. */
package/dist/index.js CHANGED
@@ -1,4 +1,6 @@
1
1
  export { THEME_COOKIE, THEME_EVENT, THEME_MAX_AGE_SECONDS, THEME_STORAGE_KEY, ThemeToggle, applyTheme, clearTheme, getStoredTheme, getSystemTheme, resolveEffectiveTheme, setTheme, subscribeTheme, themeInitScript } from './chunk-NQD3M7ZY.js';
2
+ export { LocalNetworkBar } from './chunk-7TBML5Q7.js';
3
+ export { communityPublications, findPublicationByHost, findPublicationBySlug, getNetworkPublicationUrl, listedPublications, localPublications } from './chunk-5W4EMBFY.js';
2
4
  import { definePublication } from './chunk-C7JTEHTH.js';
3
5
  export { BROADSHEET_THEME, FEATURE_NAMES, LAYOUT_COOKIE, acceptRemoteRecord, acceptSnapshot, definePublication, featureEnabled, parseSnapshot, publicationFromSnapshot, publicationRecord, resolveLayout, snapshotFromRecord, syncPublication } from './chunk-C7JTEHTH.js';
4
6
  export { CLASSIFIED_CATEGORIES, JOB_EMPLOYMENT_TYPES, categoryLabel, classifiedPath, classifiedSearchPath, clipChars, dealDollars, dealGoPath, dealsFeedPath, employmentLabel, isClassifiedCategory, isEmploymentType, jobEmployerBody, jobOpeningBody, jobPostingBody, prepareClassified, prepareJobPost, publicJobPath, publicJobsPath } from './chunk-C7ZPLH2K.js';
@@ -0,0 +1,145 @@
1
+ "use client";
2
+ 'use strict';
3
+
4
+ var react = require('react');
5
+ var compliance = require('@scalemule/compliance');
6
+ var jsxRuntime = require('react/jsx-runtime');
7
+
8
+ // src/network.ts
9
+ var localPublications = [
10
+ {
11
+ slug: "bayareachronicle",
12
+ name: "Bay Area Chronicle",
13
+ url: "https://bayareachronicle.com",
14
+ area: "San Francisco Bay Area",
15
+ description: "The parent home for our local community publications."
16
+ },
17
+ {
18
+ slug: "concordchronicle",
19
+ name: "Concord Chronicle",
20
+ url: "https://concordchronicle.com",
21
+ area: "Concord",
22
+ description: "A new place for Concord\u2019s local stories, independent businesses and community voices."
23
+ },
24
+ {
25
+ slug: "walnutcreektimes",
26
+ name: "Walnut Creek Times",
27
+ url: "https://walnutcreektimes.com",
28
+ area: "Walnut Creek \xB7 Rossmoor \xB7 Saranap \xB7 Pleasant Hill",
29
+ description: "A new place for Walnut Creek\u2019s local stories, independent businesses and community voices."
30
+ },
31
+ {
32
+ slug: "lamorindapost",
33
+ name: "Lamorinda Post",
34
+ url: "https://lamorindapost.com",
35
+ area: "Orinda \xB7 Lafayette \xB7 Moraga",
36
+ description: "A new home for the neighbors, businesses and community stories of Lamorinda."
37
+ },
38
+ {
39
+ slug: "alamoweekly",
40
+ name: "Alamo Weekly",
41
+ url: "https://alamoweekly.com",
42
+ area: "Alamo",
43
+ description: "A new place for Alamo\u2019s local stories, independent businesses and community voices."
44
+ },
45
+ {
46
+ slug: "danvilletimes",
47
+ name: "Danville Times",
48
+ url: "https://danvilletimes.com",
49
+ area: "Danville",
50
+ description: "A new place for Danville\u2019s local stories, independent businesses and community voices."
51
+ },
52
+ {
53
+ slug: "sanramontimes",
54
+ name: "San Ramon Times",
55
+ url: "https://sanramontimes.com",
56
+ area: "San Ramon",
57
+ description: "A new place for San Ramon\u2019s local stories, independent businesses and community voices."
58
+ },
59
+ {
60
+ slug: "diablovalleynews",
61
+ name: "Diablo Valley News",
62
+ url: "https://diablovalleynews.com",
63
+ area: "Concord \xB7 Walnut Creek \xB7 Pleasant Hill \xB7 Alamo \xB7 Danville \xB7 San Ramon",
64
+ description: "Local stories about the people, businesses and community life of the Diablo Valley."
65
+ },
66
+ {
67
+ slug: "trivalleyweekly",
68
+ name: "Tri-Valley Weekly",
69
+ url: "https://trivalleyweekly.com",
70
+ area: "Alamo \xB7 Danville \xB7 San Ramon \xB7 Dublin \xB7 Pleasanton \xB7 Livermore",
71
+ description: "Local stories about the businesses, people and community life of the Tri-Valley."
72
+ },
73
+ {
74
+ slug: "eastbaypost",
75
+ name: "East Bay Post",
76
+ url: "https://eastbaypost.com",
77
+ area: "The East Bay",
78
+ description: "A new publication connecting the people and neighborhoods of the East Bay."
79
+ },
80
+ {
81
+ slug: "napagate",
82
+ name: "Napa Gate",
83
+ url: "https://napagate.com",
84
+ area: "Napa Valley",
85
+ description: "A new local publication for the people, places and everyday life of Napa Valley.",
86
+ listed: false
87
+ }
88
+ ];
89
+ var listedPublications = localPublications.filter(
90
+ (publication) => !("listed" in publication) || publication.listed
91
+ );
92
+ listedPublications.filter(
93
+ (publication) => publication.slug !== "bayareachronicle"
94
+ );
95
+ function LocalNetworkBar({ currentSlug, className = "", style }) {
96
+ const [open, setOpen] = react.useState(false);
97
+ const id = react.useId();
98
+ const button = react.useRef(null);
99
+ return /* @__PURE__ */ jsxRuntime.jsx(
100
+ "nav",
101
+ {
102
+ className: `sm-network-bar ${className}`.trim(),
103
+ style,
104
+ "aria-label": "Local publication network",
105
+ onKeyDown: (e) => {
106
+ if (e.key === "Escape" && open) {
107
+ setOpen(false);
108
+ button.current?.focus();
109
+ }
110
+ },
111
+ children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "sm-network-inner", children: [
112
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "sm-network-label", children: "Our local sites" }),
113
+ /* @__PURE__ */ jsxRuntime.jsxs(
114
+ "button",
115
+ {
116
+ className: "sm-network-selector",
117
+ ref: button,
118
+ "aria-expanded": open,
119
+ "aria-controls": id,
120
+ onClick: () => setOpen(!open),
121
+ type: "button",
122
+ children: [
123
+ "Our local sites ",
124
+ /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": "true", children: open ? "\u2212" : "+" })
125
+ ]
126
+ }
127
+ ),
128
+ /* @__PURE__ */ jsxRuntime.jsx("ul", { id, className: `sm-network-sites ${open ? "sm-network-expanded" : ""}`, "aria-label": "All local publications", children: listedPublications.map((publication) => {
129
+ const isCurrent = publication.slug === currentSlug;
130
+ const targetUrl = isCurrent ? publication.url + "/" : compliance.decorateNetworkUrl(publication.url + "/");
131
+ return /* @__PURE__ */ jsxRuntime.jsx("li", { children: /* @__PURE__ */ jsxRuntime.jsx(
132
+ "a",
133
+ {
134
+ href: targetUrl,
135
+ "aria-current": isCurrent ? "true" : void 0,
136
+ children: publication.name
137
+ }
138
+ ) }, publication.slug);
139
+ }) })
140
+ ] })
141
+ }
142
+ );
143
+ }
144
+
145
+ exports.LocalNetworkBar = LocalNetworkBar;
@@ -0,0 +1,15 @@
1
+ import * as react from 'react';
2
+ import { CSSProperties } from 'react';
3
+
4
+ interface LocalNetworkBarProps {
5
+ currentSlug: string;
6
+ className?: string;
7
+ style?: CSSProperties;
8
+ }
9
+ /**
10
+ * Global navigation bar for the Bay Area Local News network.
11
+ * Links across independent publication origins, transferring consent tokens automatically.
12
+ */
13
+ declare function LocalNetworkBar({ currentSlug, className, style }: LocalNetworkBarProps): react.JSX.Element;
14
+
15
+ export { LocalNetworkBar, type LocalNetworkBarProps };
@@ -0,0 +1,15 @@
1
+ import * as react from 'react';
2
+ import { CSSProperties } from 'react';
3
+
4
+ interface LocalNetworkBarProps {
5
+ currentSlug: string;
6
+ className?: string;
7
+ style?: CSSProperties;
8
+ }
9
+ /**
10
+ * Global navigation bar for the Bay Area Local News network.
11
+ * Links across independent publication origins, transferring consent tokens automatically.
12
+ */
13
+ declare function LocalNetworkBar({ currentSlug, className, style }: LocalNetworkBarProps): react.JSX.Element;
14
+
15
+ export { LocalNetworkBar, type LocalNetworkBarProps };
@@ -0,0 +1,3 @@
1
+ export { LocalNetworkBar } from './chunk-7TBML5Q7.js';
2
+ import './chunk-5W4EMBFY.js';
3
+ import './chunk-QWK6G2UF.js';
@@ -0,0 +1,115 @@
1
+ 'use strict';
2
+
3
+ var compliance = require('@scalemule/compliance');
4
+
5
+ // src/cookies.ts
6
+
7
+ // src/network.ts
8
+ var localPublications = [
9
+ {
10
+ slug: "bayareachronicle",
11
+ name: "Bay Area Chronicle",
12
+ url: "https://bayareachronicle.com",
13
+ area: "San Francisco Bay Area",
14
+ description: "The parent home for our local community publications."
15
+ },
16
+ {
17
+ slug: "concordchronicle",
18
+ name: "Concord Chronicle",
19
+ url: "https://concordchronicle.com",
20
+ area: "Concord",
21
+ description: "A new place for Concord\u2019s local stories, independent businesses and community voices."
22
+ },
23
+ {
24
+ slug: "walnutcreektimes",
25
+ name: "Walnut Creek Times",
26
+ url: "https://walnutcreektimes.com",
27
+ area: "Walnut Creek \xB7 Rossmoor \xB7 Saranap \xB7 Pleasant Hill",
28
+ description: "A new place for Walnut Creek\u2019s local stories, independent businesses and community voices."
29
+ },
30
+ {
31
+ slug: "lamorindapost",
32
+ name: "Lamorinda Post",
33
+ url: "https://lamorindapost.com",
34
+ area: "Orinda \xB7 Lafayette \xB7 Moraga",
35
+ description: "A new home for the neighbors, businesses and community stories of Lamorinda."
36
+ },
37
+ {
38
+ slug: "alamoweekly",
39
+ name: "Alamo Weekly",
40
+ url: "https://alamoweekly.com",
41
+ area: "Alamo",
42
+ description: "A new place for Alamo\u2019s local stories, independent businesses and community voices."
43
+ },
44
+ {
45
+ slug: "danvilletimes",
46
+ name: "Danville Times",
47
+ url: "https://danvilletimes.com",
48
+ area: "Danville",
49
+ description: "A new place for Danville\u2019s local stories, independent businesses and community voices."
50
+ },
51
+ {
52
+ slug: "sanramontimes",
53
+ name: "San Ramon Times",
54
+ url: "https://sanramontimes.com",
55
+ area: "San Ramon",
56
+ description: "A new place for San Ramon\u2019s local stories, independent businesses and community voices."
57
+ },
58
+ {
59
+ slug: "diablovalleynews",
60
+ name: "Diablo Valley News",
61
+ url: "https://diablovalleynews.com",
62
+ area: "Concord \xB7 Walnut Creek \xB7 Pleasant Hill \xB7 Alamo \xB7 Danville \xB7 San Ramon",
63
+ description: "Local stories about the people, businesses and community life of the Diablo Valley."
64
+ },
65
+ {
66
+ slug: "trivalleyweekly",
67
+ name: "Tri-Valley Weekly",
68
+ url: "https://trivalleyweekly.com",
69
+ area: "Alamo \xB7 Danville \xB7 San Ramon \xB7 Dublin \xB7 Pleasanton \xB7 Livermore",
70
+ description: "Local stories about the businesses, people and community life of the Tri-Valley."
71
+ },
72
+ {
73
+ slug: "eastbaypost",
74
+ name: "East Bay Post",
75
+ url: "https://eastbaypost.com",
76
+ area: "The East Bay",
77
+ description: "A new publication connecting the people and neighborhoods of the East Bay."
78
+ },
79
+ {
80
+ slug: "napagate",
81
+ name: "Napa Gate",
82
+ url: "https://napagate.com",
83
+ area: "Napa Valley",
84
+ description: "A new local publication for the people, places and everyday life of Napa Valley.",
85
+ listed: false
86
+ }
87
+ ];
88
+ var listedPublications = localPublications.filter(
89
+ (publication) => !("listed" in publication) || publication.listed
90
+ );
91
+ var communityPublications = listedPublications.filter(
92
+ (publication) => publication.slug !== "bayareachronicle"
93
+ );
94
+ function findPublicationBySlug(slug) {
95
+ return localPublications.find((p) => p.slug === slug);
96
+ }
97
+ function findPublicationByHost(host) {
98
+ const cleanHost = host.replace(/^https?:\/\//, "").replace(/\/.*$/, "").toLowerCase();
99
+ return localPublications.find((p) => {
100
+ const pubHost = p.url.replace(/^https?:\/\//, "").replace(/\/.*$/, "").toLowerCase();
101
+ return pubHost === cleanHost || cleanHost.startsWith(`${p.slug}.`);
102
+ });
103
+ }
104
+ function getNetworkPublicationUrl(slug) {
105
+ const pub = findPublicationBySlug(slug);
106
+ if (!pub) return null;
107
+ return compliance.decorateNetworkUrl(pub.url + "/");
108
+ }
109
+
110
+ exports.communityPublications = communityPublications;
111
+ exports.findPublicationByHost = findPublicationByHost;
112
+ exports.findPublicationBySlug = findPublicationBySlug;
113
+ exports.getNetworkPublicationUrl = getNetworkPublicationUrl;
114
+ exports.listedPublications = listedPublications;
115
+ exports.localPublications = localPublications;
@@ -0,0 +1,23 @@
1
+ interface PublicationNetworkItem {
2
+ slug: string;
3
+ name: string;
4
+ url: string;
5
+ area: string;
6
+ description: string;
7
+ listed?: boolean;
8
+ }
9
+ /**
10
+ * Public directory of all ScaleMule local news publications in the Bay Area network.
11
+ * Menu order follows the central corridor from north to south.
12
+ */
13
+ declare const localPublications: readonly PublicationNetworkItem[];
14
+ declare const listedPublications: readonly PublicationNetworkItem[];
15
+ declare const communityPublications: readonly PublicationNetworkItem[];
16
+ /** Find a publication in the network by its slug. */
17
+ declare function findPublicationBySlug(slug: string): PublicationNetworkItem | undefined;
18
+ /** Find a publication in the network by its hostname or full origin URL. */
19
+ declare function findPublicationByHost(host: string): PublicationNetworkItem | undefined;
20
+ /** Get decorated URL for cross-domain navigation within the network with consent transfer. */
21
+ declare function getNetworkPublicationUrl(slug: string): string | null;
22
+
23
+ export { type PublicationNetworkItem, communityPublications, findPublicationByHost, findPublicationBySlug, getNetworkPublicationUrl, listedPublications, localPublications };
@@ -0,0 +1,23 @@
1
+ interface PublicationNetworkItem {
2
+ slug: string;
3
+ name: string;
4
+ url: string;
5
+ area: string;
6
+ description: string;
7
+ listed?: boolean;
8
+ }
9
+ /**
10
+ * Public directory of all ScaleMule local news publications in the Bay Area network.
11
+ * Menu order follows the central corridor from north to south.
12
+ */
13
+ declare const localPublications: readonly PublicationNetworkItem[];
14
+ declare const listedPublications: readonly PublicationNetworkItem[];
15
+ declare const communityPublications: readonly PublicationNetworkItem[];
16
+ /** Find a publication in the network by its slug. */
17
+ declare function findPublicationBySlug(slug: string): PublicationNetworkItem | undefined;
18
+ /** Find a publication in the network by its hostname or full origin URL. */
19
+ declare function findPublicationByHost(host: string): PublicationNetworkItem | undefined;
20
+ /** Get decorated URL for cross-domain navigation within the network with consent transfer. */
21
+ declare function getNetworkPublicationUrl(slug: string): string | null;
22
+
23
+ export { type PublicationNetworkItem, communityPublications, findPublicationByHost, findPublicationBySlug, getNetworkPublicationUrl, listedPublications, localPublications };
@@ -0,0 +1,2 @@
1
+ export { communityPublications, findPublicationByHost, findPublicationBySlug, getNetworkPublicationUrl, listedPublications, localPublications } from './chunk-5W4EMBFY.js';
2
+ import './chunk-QWK6G2UF.js';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@scalemule/news-publication",
3
- "version": "0.0.14",
3
+ "version": "0.0.15",
4
4
  "description": "Shared server framework for ScaleMule local news publications. Walnut Creek Times is the broadsheet default; each paper supplies its own identity and feature flags.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",
@@ -59,6 +59,16 @@
59
59
  "types": "./dist/compliance.d.ts",
60
60
  "import": "./dist/compliance.js",
61
61
  "require": "./dist/compliance.cjs"
62
+ },
63
+ "./network": {
64
+ "types": "./dist/network.d.ts",
65
+ "import": "./dist/network.js",
66
+ "require": "./dist/network.cjs"
67
+ },
68
+ "./network-bar": {
69
+ "types": "./dist/network-bar.d.ts",
70
+ "import": "./dist/network-bar.js",
71
+ "require": "./dist/network-bar.cjs"
62
72
  }
63
73
  },
64
74
  "files": [