diff --git a/docs/README.md b/docs/README.md index ff61c07..caeb0d8 100644 --- a/docs/README.md +++ b/docs/README.md @@ -18,6 +18,7 @@ This directory contains the working documentation for the WeatherTool modernizat - [Development and staging](DEVELOPMENT_AND_STAGING.md) — Git workflow, local build, Rocky deployment, synthetic data, verification, and rollback. - [Product workflows](PRODUCT_WORKFLOWS.md) — the intended purpose and current status of each visible workspace. - [Update roadmap](UPDATE_ROADMAP.md) — phased technical, security, dependency, testing, and UI work. +- [Third-party notices](THIRD_PARTY_NOTICES.md) — licenses and attribution for adapted interface components. ## Documentation rules @@ -25,4 +26,3 @@ This directory contains the working documentation for the WeatherTool modernizat 2. Document the behavior that exists separately from behavior that is proposed. 3. Update these documents in the same commit when a change alters deployment, data flow, or a user workflow. 4. Keep synthetic/development instructions clearly distinguished from workplace production procedures. - diff --git a/docs/THIRD_PARTY_NOTICES.md b/docs/THIRD_PARTY_NOTICES.md new file mode 100644 index 0000000..0b3fe16 --- /dev/null +++ b/docs/THIRD_PARTY_NOTICES.md @@ -0,0 +1,15 @@ +# Third-party notices + +The frontend interaction styling includes adapted ideas from the following MIT-licensed Uiverse components: + +- Checkbox by Galahhad: https://uiverse.io/Galahhad/sweet-ape-100 +- Button by e-coders (Aasheesh Agarwal): https://uiverse.io/e-coders/new-shrimp-32 + +Copyright © 2026 Galahhad (Galahad) +Copyright © 2026 e-coders (E - Coders / Aasheesh Agarwal) + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/web/src/css/index.css b/web/src/css/index.css index d3fe29e..26968fb 100644 --- a/web/src/css/index.css +++ b/web/src/css/index.css @@ -3,7 +3,7 @@ body { margin: 0; font-family: Inter,ui-sans-serif,system-ui,-apple-system,"Segoe UI",sans-serif; - color:var(--text);background:#f3f5f8; + color:var(--text);background-color:#edf3fb;background-image:radial-gradient(circle at 8% 4%,rgba(95,157,230,.14),transparent 30%),radial-gradient(circle at 92% 18%,rgba(99,196,218,.12),transparent 28%),linear-gradient(145deg,#f4f8fd 0%,#edf4fc 48%,#eaf1fb 100%);background-attachment:fixed; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; } @@ -41,6 +41,9 @@ thead { } .primary{background:var(--accent);color:#fff}.primary:hover{background:var(--accent-strong)} +button,input[type=button]{transition:transform 260ms cubic-bezier(.23,1,.32,1),box-shadow 260ms,background-color 180ms,border-color 180ms;touch-action:manipulation;will-change:transform}button:not(:disabled):hover,input[type=button]:not(:disabled):hover{transform:translateY(-2px);box-shadow:0 8px 16px rgba(26,74,128,.16)}button:not(:disabled):active,input[type=button]:not(:disabled):active{transform:translateY(0);box-shadow:none} +input[type=checkbox]{--checkbox-size:18px;appearance:none;width:var(--checkbox-size);height:var(--checkbox-size);margin:0 6px 0 0;vertical-align:-3px;border:1px solid #aebed1;border-radius:5px;background:#fff;cursor:pointer;position:relative;transition:all .25s}input[type=checkbox]:hover{border-color:var(--accent)}input[type=checkbox]:checked{border-color:transparent;background:linear-gradient(145deg,#3388d7,#1763aa);box-shadow:0 0 0 3px rgba(36,119,197,.13)}input[type=checkbox]:checked:before{content:"";position:absolute;top:45%;left:50%;width:4px;height:8px;border-right:2px solid #fff;border-bottom:2px solid #fff;transform:translate(-50%,-50%) rotate(45deg) scale(1);animation:check-pop .22s cubic-bezier(.12,.4,.29,1.46)}input[type=checkbox]:focus-visible{outline:3px solid var(--accent-soft);outline-offset:2px}@keyframes check-pop{from{opacity:0;transform:translate(-50%,-50%) rotate(45deg) scale(0)}to{opacity:1;transform:translate(-50%,-50%) rotate(45deg) scale(1)}} +@media(prefers-reduced-motion:reduce){*,*:before,*:after{scroll-behavior:auto!important;animation-duration:.01ms!important;animation-iteration-count:1!important;transition-duration:.01ms!important}} input[type=text],input[type=date],input[type=datetime-local],select{min-height:38px;padding:7px 10px;border:1px solid #cfd7e2;border-radius:8px;background:#fff}button:disabled,input:disabled{cursor:not-allowed;opacity:.48}.appContent{min-height:calc(100vh - 73px)} table td { diff --git a/web/src/css/menu.module.css b/web/src/css/menu.module.css index bfae99c..d5c808c 100644 --- a/web/src/css/menu.module.css +++ b/web/src/css/menu.module.css @@ -1,3 +1,4 @@ -.header{position:sticky;top:0;z-index:100;display:flex;align-items:center;justify-content:space-between;gap:28px;min-height:72px;padding:0 30px;border-bottom:1px solid var(--border);background:rgba(249,250,252,.92);backdrop-filter:blur(16px)} +.header{position:sticky;top:0;z-index:100;display:flex;align-items:center;justify-content:space-between;gap:28px;min-height:72px;padding:0 30px;border-bottom:1px solid rgba(99,145,202,.25);background:linear-gradient(110deg,rgba(247,251,255,.94),rgba(226,238,255,.92),rgba(239,247,255,.94));backdrop-filter:blur(18px)} +.brandMark{background:linear-gradient(145deg,#398bd8,#15579b)!important;box-shadow:0 7px 16px rgba(26,91,157,.22)} .brand{display:flex;align-items:center;gap:11px;color:var(--text);text-decoration:none}.brandMark{display:grid;place-items:center;width:38px;height:38px;border-radius:11px;background:var(--accent);color:#fff;font-family:Rubik,sans-serif;font-size:19px}.brand strong,.brand small{display:block}.brand small{margin-top:2px;color:var(--text-muted);font-size:11px}.menu{display:flex;align-items:center;gap:4px;margin:0;padding:0;list-style:none}.menu li{margin:0;padding:0}.menu a{display:block;padding:10px 12px;border-radius:9px;color:var(--text-muted);font-size:13px;font-weight:700;text-decoration:none}.menu a:hover{background:var(--surface-strong);color:var(--text)}.menu a.active{background:var(--accent-pale);color:var(--accent-strong)} @media(max-width:980px){.header{align-items:flex-start;flex-direction:column;padding:14px 18px}.menu{max-width:100%;overflow-x:auto}.menu a{white-space:nowrap}} diff --git a/web/src/pages/home/Home.tsx b/web/src/pages/home/Home.tsx index 8ad5511..35521c9 100644 --- a/web/src/pages/home/Home.tsx +++ b/web/src/pages/home/Home.tsx @@ -2,12 +2,12 @@ import { A } from '@solidjs/router' import './home.css' const tools = [ - ['/station','Monitor','Stations','Inspect recent measurements on a map and open detailed station charts.','◉'], - ['/cities','Analyse & export','City analysis','Compare cities, aggregate values, and prepare temperature maps.','▦'], - ['/faktiska','Daily production','Faktiskā','Build the actual-weather map with temperatures, weather symbols, title, and source.','▣'], - ['/latvia','Summarise','Latvia overview','Review country-wide minimum, maximum, average, and total values.','⌁'], - ['/database','Browse','Data archive','Find available dates and inspect individual hourly records.','▤'], - ['/harmonie','Forecast model','HARMONIE','Render forecast fields from locally stored HARMONIE GRIB files.','◫'], - ['/lvgmc-forecast','Forecast products','LVĢMC forecast','Open prepared LVĢMC city forecasts and broadcast tables.','☁'], + ['/station','Stations','Recent measurements and station charts.','◉'], + ['/cities','City analysis','Compare values and prepare temperature maps.','▦'], + ['/faktiska','Faktiskā','Temperatures and weather symbols for daily production.','▣'], + ['/latvia','Latvia overview','Country-wide weather summaries.','⌁'], + ['/database','Data archive','Browse dates and stored observations.','▤'], + ['/harmonie','HARMONIE','Render locally stored forecast fields.','◫'], + ['/lvgmc-forecast','LVĢMC forecast','Prepared city forecasts and broadcast tables.','☁'], ] -export function Home() { return

Weather data and production tools

Choose a workspace

Explore station history, compare cities, inspect forecasts, or prepare weather graphics from one place.

Development datasetSynthetic station observations are active
{tools.map(([path,eyebrow,title,description,icon]) => {icon}{eyebrow}

{title}

{description}

Open workspace →
)}
} +export function Home() { return

Weather data and production tools

Choose a workspace

Analysis, forecasts and newsroom graphics.

Development datasetSynthetic observations
{tools.map(([path,title,description,icon]) => {icon}

{title}

{description}

)}
} diff --git a/web/src/pages/home/home.css b/web/src/pages/home/home.css index 6d37b83..fbb14e7 100644 --- a/web/src/pages/home/home.css +++ b/web/src/pages/home/home.css @@ -1 +1 @@ -.homePage{max-width:1440px;margin:auto;padding:56px 32px 80px}.homeHero{display:flex;justify-content:space-between;align-items:end;gap:48px;margin-bottom:40px}.homeHero h1{margin:8px 0 14px;font-size:clamp(38px,5vw,68px);line-height:.98;letter-spacing:-.045em}.heroCopy{max-width:720px;margin:0;color:var(--text-muted);font-size:18px;line-height:1.6}.eyebrow{color:var(--accent-strong);font-size:12px;font-weight:700;letter-spacing:.12em;text-transform:uppercase}.environmentBadge{min-width:250px;padding:16px 18px;border:1px solid var(--border);border-radius:14px;background:var(--surface);font-weight:700;box-shadow:var(--shadow-sm)}.environmentBadge small{display:block;margin:5px 0 0 18px;color:var(--text-muted);font-weight:400}.statusDot{display:inline-block;width:9px;height:9px;margin-right:9px;border-radius:50%;background:var(--success);box-shadow:0 0 0 4px rgba(38,147,104,.12)}.toolGrid{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:18px}.toolCard{position:relative;min-height:230px;padding:26px;overflow:hidden;border:1px solid var(--border);border-radius:18px;background:var(--surface);color:var(--text);text-decoration:none;box-shadow:var(--shadow-sm);transition:.18s}.toolCard:hover{transform:translateY(-3px);border-color:var(--accent-soft);box-shadow:var(--shadow-md)}.toolCard h2{margin:28px 0 10px;font-size:24px}.toolCard p{max-width:90%;margin:0;color:var(--text-muted);line-height:1.55}.toolIcon{position:absolute;top:20px;right:22px;color:var(--accent);font-size:31px}.cardAction{position:absolute;bottom:24px;left:26px;font-weight:700}@media(max-width:960px){.toolGrid{grid-template-columns:repeat(2,1fr)}.homeHero{align-items:start;flex-direction:column}}@media(max-width:640px){.homePage{padding:36px 18px}.toolGrid{grid-template-columns:1fr}} +.homePage{position:relative;max-width:1440px;margin:auto;padding:52px 32px 80px}.homePage:before{content:"";position:absolute;z-index:-1;top:-90px;right:4%;width:430px;height:430px;border-radius:50%;background:radial-gradient(circle,rgba(65,132,226,.18),transparent 68%);filter:blur(10px)}.homeHero{display:flex;justify-content:space-between;align-items:end;gap:48px;margin-bottom:32px}.homeHero h1{margin:7px 0 10px;font-size:clamp(38px,5vw,64px);line-height:1;letter-spacing:-.045em}.heroCopy{margin:0;color:var(--text-muted);font-size:16px}.eyebrow{color:var(--accent-strong);font-size:12px;font-weight:700;letter-spacing:.12em;text-transform:uppercase}.environmentBadge{min-width:220px;padding:13px 16px;border:1px solid rgba(116,158,211,.35);border-radius:14px;background:linear-gradient(135deg,rgba(255,255,255,.88),rgba(225,238,255,.82));font-weight:700;box-shadow:var(--shadow-sm);backdrop-filter:blur(12px)}.environmentBadge small{display:block;margin:3px 0 0 18px;color:var(--text-muted);font-weight:400}.statusDot{display:inline-block;width:9px;height:9px;margin-right:9px;border-radius:50%;background:var(--success);box-shadow:0 0 0 4px rgba(38,147,104,.12)}.toolGrid{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:18px}.toolCard{position:relative;display:flex;min-height:180px;padding:24px;overflow:hidden;border:1px solid rgba(115,154,204,.28);border-radius:20px;background:linear-gradient(145deg,rgba(255,255,255,.94),rgba(231,241,255,.78));color:var(--text);text-decoration:none;box-shadow:0 12px 30px rgba(30,77,132,.08);transition:transform 280ms cubic-bezier(.23,1,.32,1),box-shadow 280ms,border-color 280ms}.toolCard:before{content:"";position:absolute;inset:auto -55px -70px auto;width:155px;height:155px;border-radius:50%;background:radial-gradient(circle,rgba(43,117,211,.16),transparent 70%);transition:transform 350ms}.toolCard:nth-child(3n+2){background:linear-gradient(145deg,rgba(255,255,255,.94),rgba(226,235,255,.82))}.toolCard:nth-child(3n){background:linear-gradient(145deg,rgba(255,255,255,.94),rgba(220,242,250,.8))}.toolCard:hover{transform:translateY(-4px);border-color:rgba(36,119,197,.5);box-shadow:0 18px 38px rgba(30,77,132,.16)}.toolCard:hover:before{transform:scale(1.18)}.toolCard:active{transform:translateY(0);box-shadow:0 8px 18px rgba(30,77,132,.1)}.toolCardCopy{align-self:flex-end;position:relative;z-index:1}.toolCard h2{margin:0 0 7px;font-size:clamp(27px,2.2vw,34px);letter-spacing:-.025em}.toolCard p{max-width:85%;margin:0;color:var(--text-muted);font-size:13px;line-height:1.45}.toolIcon{position:absolute;top:18px;left:22px;display:grid;place-items:center;width:56px;height:56px;border:1px solid rgba(57,126,209,.22);border-radius:17px;background:linear-gradient(145deg,#f8fbff,#dcecff);color:var(--accent);font-size:32px;box-shadow:0 8px 18px rgba(37,103,180,.12)}.cardArrow{position:absolute;right:22px;bottom:20px;color:var(--accent-strong);font-size:22px;font-weight:700;transition:transform 200ms}.toolCard:hover .cardArrow{transform:translateX(4px)}@media(max-width:960px){.toolGrid{grid-template-columns:repeat(2,1fr)}.homeHero{align-items:start;flex-direction:column}}@media(max-width:640px){.homePage{padding:36px 18px}.toolGrid{grid-template-columns:1fr}}