From 47811106d2818b376a6736b2afc260528bbcaaaa Mon Sep 17 00:00:00 2001 From: gadgethd <111318106+gadgethd@users.noreply.github.com> Date: Sun, 9 Aug 2026 02:45:59 +0000 Subject: [PATCH] feat(site): add /contact page with operator Discord + email, footer link Contact page (site footer -> Contact) with Discord sudogadget and ukmesh@proton.me, plus an observer-onboarding blurb. Wired into publicRoutes (sitemap: true), lazy-loaded ContactPage chunk, and the shared SiteLayout footer (app + website surfaces). Re-baselined website-live-manifest.json for the new website image (e5db6790). --- frontend/src/config/publicRoutes.ts | 10 ++- frontend/src/main.tsx | 2 + frontend/src/pages/ContactPage.tsx | 33 ++++++++ frontend/src/pages/shared/SiteLayout.tsx | 2 + website-live-manifest.json | 102 ++++++++++++----------- 5 files changed, 98 insertions(+), 51 deletions(-) create mode 100644 frontend/src/pages/ContactPage.tsx diff --git a/frontend/src/config/publicRoutes.ts b/frontend/src/config/publicRoutes.ts index 0937f94..c05c5f4 100644 --- a/frontend/src/config/publicRoutes.ts +++ b/frontend/src/config/publicRoutes.ts @@ -9,7 +9,8 @@ export type PublicRouteComponent = | 'open-source' | 'stats' | 'spam' - | 'topology'; + | 'topology' + | 'contact'; export type PublicRouteDefinition = { path: string; @@ -28,6 +29,13 @@ export const PUBLIC_ROUTES: readonly PublicRouteDefinition[] = [ description: 'Real-time analytics for the UK MeshCore LoRa mesh network. Live packet feed, repeater coverage maps, network statistics, and install guides.', sitemap: true, }, + { + path: '/contact', + component: 'contact', + title: 'Contact — UK Mesh Network', + description: 'Get in touch with the UK Mesh operator about the site, the network, or adding your observer station.', + sitemap: true, + }, { path: '/install', component: 'install', diff --git a/frontend/src/main.tsx b/frontend/src/main.tsx index d1b1882..bf4b74d 100644 --- a/frontend/src/main.tsx +++ b/frontend/src/main.tsx @@ -19,6 +19,7 @@ import { const App = lazy(() => import('./App.js').then(({ App: Component }) => ({ default: Component }))); const OpenSourcePage = lazy(() => import('./pages/OpenSourcePage.js').then(({ OpenSourcePage: Component }) => ({ default: Component }))); const StatsPage = lazy(() => import('./pages/StatsPage.js').then(({ StatsPage: Component }) => ({ default: Component }))); +const ContactPage = lazy(() => import('./pages/ContactPage.js').then(({ ContactPage: Component }) => ({ default: Component }))); const OwnerPortalPage = lazy(() => import('./pages/OwnerPortalPage.js').then(({ OwnerPortalPage: Component }) => ({ default: Component }))); const UKLayout = lazy(() => import('./pages/ukmesh/UKLayout.js').then(({ UKLayout: Component }) => ({ default: Component }))); const UKHomePage = lazy(() => import('./pages/ukmesh/UKHomePage.js').then(({ UKHomePage: Component }) => ({ default: Component }))); @@ -43,6 +44,7 @@ const PUBLIC_ROUTE_ELEMENTS: Record = stats: , spam: , topology: , + contact: , }; const root = document.getElementById('root')!; diff --git a/frontend/src/pages/ContactPage.tsx b/frontend/src/pages/ContactPage.tsx new file mode 100644 index 0000000..c40e2d1 --- /dev/null +++ b/frontend/src/pages/ContactPage.tsx @@ -0,0 +1,33 @@ +import React from 'react'; + +export const ContactPage: React.FC = () => ( +
+
+

Contact

+

+ Questions about the site, the network, or joining as an observer? Get in touch + directly — UK Mesh is run by one person and everything sent this way gets read. +

+
+
+

Ways to reach me

+
    +
  • + Discord: sudogadget — best for quick questions about + the site, the mesh, or getting your observer station added. +
  • +
  • + Email: ukmesh@proton.me — for + anything longer, or if you prefer email. +
  • +
+
+
+

Adding an observer

+

+ Want your station feeding the live map? Message me on Discord or email with your + node's name and public key and I'll get you set up with an account. +

+
+
+); diff --git a/frontend/src/pages/shared/SiteLayout.tsx b/frontend/src/pages/shared/SiteLayout.tsx index e510df4..051bbd3 100644 --- a/frontend/src/pages/shared/SiteLayout.tsx +++ b/frontend/src/pages/shared/SiteLayout.tsx @@ -231,6 +231,8 @@ export const SiteLayout: React.FC = ({ · Discord · + Contact + · Stats · Open Source diff --git a/website-live-manifest.json b/website-live-manifest.json index 1c57fc4..a301bce 100644 --- a/website-live-manifest.json +++ b/website-live-manifest.json @@ -1,45 +1,46 @@ { - "captured": "2026-08-08T01:11:39Z", - "fileCount": 75, + "captured": "2026-08-09T02:45:51Z", + "fileCount": 77, "files": { "50x.html": "876766b4e80133fd490603e073d3567425b88794828a9292104244c9e40875ed", - "assets/App-C8Ome_t9.js": "e50cf599fd514fbe29f50fa7e6a16c803f99d2fa89e53d702e0830c7afb88cc1", + "assets/App-BDHUqBpQ.js": "e92a8d22c81f98a42472d8a9afc22992352a576328f18e861c27b169f794433d", "assets/App-oN66RUc2.css": "f6224045099ed56d1220de566bb8ba78c67bd6563b85d51fc99db976cf95b075", - "assets/AreaChart-CYSMORwh.js": "f4ac734b8348f9611ee221c3337f5d53a6461234825a26ed95fd05c1a457d27e", - "assets/Combobox-BkNidtIq.js": "7e22d8e84145938f56034caedea53b0a101dcf1f1a332709efee2f6f6d534e47", - "assets/Dialog-BZsDpYJT.js": "6e1e2f8365b53f7171619b5a5cf2a45cb07b16e5257dde90b9bea5bb1375ccac", - "assets/Dialog-CoY0YOSQ.js": "c95001ae93cc8635f27c01878282d12155e227d4222b56a9f2a6c633905841b6", - "assets/LazyChartMount-CUxTORl5.js": "23025b3c287155080ca55d97702e7151ff149aba80a05f585f50fac8f3548318", - "assets/LineChart-CJDhOZ-E.js": "36a3daf4d2e44db7b6827c65d2172a3138faa265c0d8c1cd7b9c76bd152a0447", - "assets/MapLibreMap-Bj2PSBES.js": "0d27bfde796dfcf47ce5f60b4a4d84fcc4745d0a30cdef5d9de62a2534a69407", - "assets/NotFoundPage-B-9hpUfM.js": "1fe7148c8ee5a2bcbc36dacc487c780532fc0139dbccc25816eac5bd39c9c30d", - "assets/ObserverRegistrationForm-DbO2caGm.js": "7be2795bc5b2ed49680666647c3d60ef3e72d4bc1abf44f9ce601067ae9a647c", - "assets/OpenSourcePage-RLgMTh8M.js": "ec6cb76d5209d754f58cbe74fdae648fea32d348dd69d7d0145719f553f6376d", + "assets/AreaChart-BFNaPjhm.js": "41e6e2865440e2fcbc46b4bbd5ce333080c4fba610e5e0a2c2ffc17c7da0d05f", + "assets/Combobox-DiJLbHZc.js": "71eeb111ff985e4b248cb6a2515a5ab5616ef0b301e90637ac58b624ad41b7f6", + "assets/ContactPage-DM2PT1x0.js": "3447ccebe5f8e41bdf6fce49de6cab395ba435b38780d0d4403ae96624efdfeb", + "assets/Dialog-6_HczqBb.js": "39240a4bda2ded60124a85bce2b33f6b81a3147b2d26873fa70ebb8e4e27e03d", + "assets/Dialog-DqQyVuJi.js": "3929fec525d5a405d4741593efc70dd14c7165e2c2f0873819eecbb585e0f413", + "assets/LazyChartMount-mGp8aVaq.js": "8e07f51694fbaf7cc11fc258eb7e6f60ae330c11b1c84fb06bc9d3e3640c7f6b", + "assets/LineChart-ByEwhLQI.js": "dc544ea2f1f340a9a127edd10fc10d6f0b3d8888a6beefa13e0ebe9b14a1fae2", + "assets/MapLibreMap-C3GTskhB.js": "a395b9ab7228adaf2c5669579a43f7a17c082aa0e74031795fd69c1520c84885", + "assets/NotFoundPage-DafsNFhu.js": "b3acc801c13efc21e9862c3c44e4866a8d22004627fa8ab39578fbf5b2b600c7", + "assets/ObserverRegistrationForm-DrDw1aAf.js": "799dda93d0f9716876b7864dab25011814cd4339be9e93d91e5dc4f9a7f2dfe3", + "assets/OpenSourcePage-BoYeNBgV.js": "b3c08c24736252e742ff17ccaf88ded368a12109919810fcbadf767aaeaecc67", "assets/OwnerPortalPage-C9R6jsV-.css": "86985def763aedb396d011d59ca458327793ad17451598aa2bb9b6696e5f65cf", - "assets/OwnerPortalPage-DK0O3Rvg.js": "5de124cf81ef3240c02f2a1e237d59f2fbf5263c0133ff736569d536a50e7e85", - "assets/PlannerComparison-De9P-Z5i.js": "22f616539d784336579770a751a57692a95a835314499408123fd2865c72823a", + "assets/OwnerPortalPage-DktWUGfG.js": "25fa3daee292651953b06e671cfd95c44a0bd376a670fa7d564f67c8794942c2", + "assets/PlannerComparison-C7-KF2PW.js": "f3ea4e221d753a2a910c32e9ea45e59fd1a6591eace6c03fe120dc3d4b777f83", "assets/SpamTransparencyPage-Cgpd8zrF.css": "5c8a1ee75e8d7f49bb0d50d54a0bdfa025fb81555c7f66dce22b10fa716eef98", - "assets/SpamTransparencyPage-D6meliLN.js": "b42cf95ff41bd910616313fafbb208cb9eb30727e7fbff6b368a179ba2615308", + "assets/SpamTransparencyPage-DO7bbQ75.js": "27b3abab7b60b0dc6ece07fe3c75e4194f6d828c841c10f5d88c8c1ca2310e9a", "assets/StatsPage-CIUCRYVb.css": "495410b180aa16341bfb5ed90c309eb039358861e2127bf11486c7c362521e22", - "assets/StatsPage-D1WHgykh.js": "55904bb743924efdfe898159ec601667a142820b27601e41fe7c63ebc810408f", - "assets/Tabs-DvZ5eDf6.js": "00e49980047ec485708b065f9c449d41a8166b99446c7e259b83815e12d2cf30", - "assets/TimelineControl-CIn7Arz_.js": "0af424fad6a0e7c5bca33f8389e5f953ddb35f277b01eadc27b16cd49f4e8a67", - "assets/TopologyPage-B4Fb11Mq.js": "8dac3a4079b636cd41702ae211fadef8d3e55e946d6214c2ba44eee4d224eea8", + "assets/StatsPage-w_c9TvLS.js": "23bf1a9f10bc2ce3e14ada731eb9487ee050217f6b601b0d5d8577616301f727", + "assets/Tabs-DcpL9NDM.js": "14bde0b803f9c80d64eef70b62cb69c234de756abd1708b1b51fad1ef3f51a22", + "assets/TimelineControl-DUAbGZes.js": "c6e21962043a91310277a457a3a3e29cde80266f2759b5c02acd9bf2b442041f", + "assets/TopologyPage-C_dXg6D1.js": "b27843e51a57d78b21065b66ec3745731752f161895163c49391d7a58f6b9e10", "assets/TopologyPage-DW9RsZIy.css": "7dba796e8d9b2160956b8ad26278554bc45053f3ac9277b9f7f896415a2fe0a3", - "assets/UKBestPracticePage-BT-2RqxR.js": "c033632a77eed02d0c7704cc77a8219d6b7f8f36ea10e526bb5a98514d8c8a15", - "assets/UKCompanionPage-VJ9MO36g.js": "3e5bfebefed8fa7057e6ef627eb83e951db88cfcea2215198177e484d31ff751", + "assets/UKBestPracticePage-DgRPwcdw.js": "75f9aeccf5758414b6c61dbd4bdf0f3b2590e495f734dbb62d341ee8f4ea2bff", + "assets/UKCompanionPage-DuTEFyql.js": "db976b2d1fe02dccff13d8bb0ac74598e4ecd31ae78053578b0bc623a38bd732", "assets/UKFeedPage-DPt7fUU5.css": "58ab284609abe5e7a0cac02f81d2467011228255c7403946b3e12fe3982fb098", - "assets/UKFeedPage-Doduv14K.js": "6bc305d200057de37b83ae0cb04894e88082d94e13744ada214107301a34e459", - "assets/UKHomePage-CDseD6kY.js": "6583ec3ca308cfd8c49b6978737b559587bf09afca0fb495de8936bd2bb4f532", - "assets/UKInstallPage-BFcNtZZl.js": "772c940dc769f570f265860162eb134091cf03241a8825ae4185d4deb12046b1", - "assets/UKLayout-cDIzTl2I.js": "7c88ea1c9e6ee119ccf3599c180b16d4b456de95ab6271b05b792a71b4fcf293", + "assets/UKFeedPage-Dhvf6Q7_.js": "1f6ee5a8a36a47ff343fee377ace319a51bc7009d43e146a7ace23f189e14671", + "assets/UKHomePage-DzCRoAXr.js": "ecdd0fb2ffe8d7a3f334ae133b1b84d69cdc6109e3c24cf0956ddf2b2dc0e4ed", + "assets/UKInstallPage-sk0SnePl.js": "b3ba44bcc98c8b82b4b61c6b1af6bac245e759234275ae80bec33f31e9201b86", + "assets/UKLayout-_LGUkuxa.js": "995fdc936b9227ef49b3912285172d1f1f45a6c80ca5a45b3ce1e8898b6186ab", "assets/UKLayout-w8l9E6b_.css": "317d99439c3ef9c10ad49e2aa5beb4cea670c20217f83be2731b2de8a23c13a2", - "assets/UKRepeaterSearchPage-BLdN16Gc.js": "2f3fbf332462235be965053bf4d997d93a989bc51a3b6d2a9a2dd1e1b241cc00", + "assets/UKRepeaterSearchPage-DOW1_90L.js": "f6df495bc0e08b1a305ccdbeae2fb7865b8acfe3f72208fe257b88d4373fc777", "assets/api-BfzueihH.js": "bef003f072283fd5e3f14b29890f7610adf3fb9808e8c6e700bd48d3e7a8bc87", "assets/clsx-B-dksMZM.js": "c7b843bc2bba461110e5ddf916d9c40180a383804ce73658730ec46e5196d2fd", - "assets/generateCategoricalChart-C7roe_Wc.js": "c5783d3f4e67e6d15ce79333f4a32a1d0768da08b01a27f969dce1101543ea82", - "assets/index-BF1vRSvu.js": "0b8a4832d8c84012c04b5e907f4739b30a5c8e183fa8a3979c3a491aece7361d", + "assets/generateCategoricalChart-ptr00sIK.js": "294ebce958c4201501d3e0ea2563a9b287d83c675831fa025b9467edde7396be", "assets/index-CLePEFXU.css": "9f24956a5ccfa13d7d8dce48cfb9ddfb621eb673b9d2e1f96d75306aae58805e", + "assets/index-CPOyfqd-.js": "85327dbb64ee615674fe6cc541ee819468227ed77641bdef045fcdbd6ed0e349", "assets/mapConfig-CMrab3U4.js": "de4c64634f5577d3bd3ae27d19ddfdca53ca317b43f679436bca9a66a9b072b9", "assets/maplibre-gl-DhHnEPbY.js": "7f1f5cd51316c56ca3e652d1d5e9859c6daf8e3ac03af29882b633591f5d16c8", "assets/maplibre-gl-PhPnDjd-.css": "5942fdb20cfdad1ab1bda9f6a2b24a0c9ce814244cc6b4689750e31e768f258c", @@ -47,39 +48,40 @@ "assets/react-CCXFnprz.js": "3f7df165326c8fab289dedc765a8750697de6e3826ef402791e1fdd27335dc59", "assets/scopedCache-C2xaKdKb.js": "ea81db76671ec528f6d553ce3c79e9fada3c8885549e39708faab8eb7b654bc4", "assets/site-BQ-PgjGR.js": "0125219201a343cc1910eab32e03defac0f15ac948d60f380d24b189cb1013d1", - "assets/useAppMessageHandler-CZTssoLj.js": "9e26420e5729b00aef7fde70440d9e516859abe3393499e43c41446f9f6a8b74", - "assets/useListState-CnxE4Jvv.js": "ad54bcad798b4dda767273581d2d12a304814cd00879f11410d3dbac6095edf5", - "assets/useNodes-BfypDh1A.js": "0adeb40641d5a2ae9f8d798f39f2a5987098036539507fd32b0e6857fee4b6eb", - "assets/useVisibilityPoll-qJ8fVL0m.js": "cdafdf57f7622397d9afff625ffa20674ba08a5400095b36f7fc9782bc030c21", - "assets/useWatchlist-BzTqBsU4.js": "012c8c4e9474a040d28842ca6041f24dc11bf583d9a4202f294d3c256cdff139", - "assets/useWebSocket-DXBGYbR_.js": "1f7915d506427c893f738befe896115684c379b15a2c675f1d0bb8cf11c6e9ae", + "assets/useAppMessageHandler-BlZFIY8L.js": "e651f484ab26c71b58960e5b948c465142244843f8486f0b9ff3afd17515ff8e", + "assets/useListState-B4ztgNPp.js": "66a5d50e64e13f3fe826fd6e443a0d4419cb7b7bfd18236a3655b906fa72ac08", + "assets/useNodes-C2RhVSMu.js": "1a26f65bad8a5ba0cc2a39bca323deb47adefca6d2b05af0c1cab9f4536236d2", + "assets/useVisibilityPoll-5SnlVyPV.js": "adf03f1ba1cd680ff742ce9811a4dfd6a800a0a1988d913ef420a4a29ed9d528", + "assets/useWatchlist-6aqKGo4t.js": "b9a54545230b58a6de682cfb590b42f43f94d0c2e21e407888f430f91ad468f8", + "assets/useWebSocket-D1VQ7VQJ.js": "d08f53038fc969c40b89612b9138c09acd28a8012d8300c2a6c60c93ec30ac6f", "assets/vite-preload-ckwbz45p.js": "b1cf8db666a7d7bfc05e8f8c93c4536728e9d086bf6f0270fa1fd0e607491519", - "companion/index.html": "7ef3289414d7f55f5945521c316370edf58e70565661721a733819e7a6fd0812", - "docs/index.html": "1eb7dc33e0761abbff12dc03a3be93b9686872ae5946f1a1e099ecceaf71700a", + "companion/index.html": "d03f6dfe09d277aca87e24204324c8582ad0723cb48869f81cf9ab332f087e1f", + "contact/index.html": "c00383e324a18b81112d216cafcb96cde21b87341cda18291ab607db960677e2", + "docs/index.html": "113abc57971cf8748f55f3a806502eae4aa450bc0890cb34740b1bdbc67a6875", "favicon-teesside.svg": "71e87888cc5929079909ffb5206d81b00bc0ddeefd0f10e53a3ec6196253dafc", "favicon.svg": "b6a63bfd7b68a436af22fd0826813ce5ece262e12e401c25d498f1daa99f3173", - "feed/index.html": "1bc3b9d95541e3656e05fd865e32a568ba6a34d976406954d284f97d5dc93a40", + "feed/index.html": "d2de73b97b81e1934e4e50e95713615a2560df54c7d4efde128fb708b661f05c", "fonts/OFL-Inter.txt": "5b9321a4298cfeb6b34354164a1c3afc3db114569984c502b9b35d988fd58c57", "fonts/OFL-ShareTechMono.txt": "9d96f445b6e9c701428811d0177f894874f8d6f07ecc30d568c506542368f3ff", "fonts/inter-latin.woff2": "3100e775e8616cd2611beecfa23a4263d7037586789b43f035236a2e6fbd4c62", "fonts/share-tech-mono-latin.woff2": "41e6b9f297f7d9a2df2aaa274092f76d2f72711a15ca455f7f4f4f92caf16b72", - "index.html": "031e22032dbd699affb35ff6721d702efe5c5ebcbe12fb0275d47fe037893b8b", - "install/index.html": "14cbb601c7f68312a30678c4059c89f799fc1221c8ce854428979b11d85389de", - "login/index.html": "f498dd7f542467223c421acef4cd76949d1fed928390e63352cb6bc64b1cbc80", + "index.html": "569e60dd7e8d8890d2015a737b40115a6c406b08228d67a538b8410cf928c787", + "install/index.html": "5fb43b5966e9e4ccf4b175e98a6e5834015562f07507267335bc3c3eb6bd72b6", + "login/index.html": "94cace4a1f3900358f7f5c2bd6b3fb477a926c0baafa5e16789327c6b8b78e13", "manifest.json": "10b409d4176794abea8626e2f6af2ec77cbef9b56795ed7bbbda71644447364b", "og-image.png": "f074e5c54f616dbbe41fdea3e3555fdaa763861d0694450c94cdeadd9b5b271e", - "open-source/index.html": "d08636bec03ee241e32c7894831d3f8f807294f6e80e464720ca0a88b21a55c3", - "repeater/index.html": "30cdfa844aad4166324e90ec329c942e424a18acfbb66a54b9009067b9e0e3fe", + "open-source/index.html": "e7dbe5b9c642c228958b41cce5ad4fbc3a05388a77fce322a2bd46feee2c4e0d", + "repeater/index.html": "4796d395ae94479d63eda7c15652f2361134f6bd542b8e97c20a6536c205e745", "robots.txt": "2e61167cf8099b06d73fa2e01ef396bc32ee4f5303da34bf46461216641c2aab", - "sitemap.xml": "52302483775c1701228438981cb9c238da0392da4da5062a8d1bba03020cf67e", - "spam/index.html": "741c118aef673cf27ecacdc85868510555518dc8405346fee8a7e0d3346076df", - "stats/index.html": "389e9ff6004f1a83b879df9bdf36f5d66ac74126975d55d0575106e3cd57e048", + "sitemap.xml": "77f90bbab57d040a51abb4791c32be0bbffd1059a16e417d37d4aa92ed5857a3", + "spam/index.html": "d10f1d8661a50e4b25c3f5de18f1165d12659504d5c06f4a1091063cb2612f5f", + "stats/index.html": "064cf000e292499b571a7ccdccdada997ce36267a89aef68c94c72461eead185", "sw-runtime.js": "3c4f3fd64ef6984751ff52c8071c918bbc719234f3ae25250ea5cccb60c9f26f", "sw.js": "4b1b59200c37f70e578c5fdff6e620b2977e23419365d758978c11b24e2266f2", - "topology/index.html": "7ef9c3237e6623165418690073e6cdac5d1a1d56407147bb20a0f1c8ffd0eb97" + "topology/index.html": "d5123722a3ba1e0168c2ca2f61147b66ec32c3fe59d3a4565fa0c4b9718ef14d" }, - "imageCreated": "2026-08-08T00:36:28.802846296Z", - "imageId": "sha256:0e37443ee557a66689de0fb64fc9541eb7ef7264b06bb98e9cdf80b22cd032b3", + "imageCreated": "2026-08-09T02:44:17.940070524Z", + "imageId": "sha256:e5db6790c3a4ea125bbd22a0d06afe87f0988922705be383ee65a9b32c1faee8", "site": "ukmesh.com", - "sourceRevisionLabel": "5210aba5e37b928db3744057beb78f2c17f92263" + "sourceRevisionLabel": "f5a2a2b93acb58b726c6798b03721f13a6938cec" } \ No newline at end of file