@jjlmoya/utils-astronomy 1.40.0 → 1.42.0
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/package.json +1 -1
- package/src/category/astronomy-category-home.css +921 -0
- package/src/category/astronomy-category-home.ts +52 -0
- package/src/category/i18n/de.ts +51 -50
- package/src/category/i18n/en.ts +16 -15
- package/src/category/i18n/es.ts +16 -15
- package/src/category/i18n/fr.ts +58 -58
- package/src/category/i18n/id.ts +20 -19
- package/src/category/i18n/it.ts +20 -19
- package/src/category/i18n/ja.ts +19 -18
- package/src/category/i18n/ko.ts +20 -19
- package/src/category/i18n/nl.ts +51 -50
- package/src/category/i18n/pl.ts +58 -57
- package/src/category/i18n/pt.ts +20 -19
- package/src/category/i18n/ru.ts +51 -50
- package/src/category/i18n/sv.ts +51 -50
- package/src/category/i18n/tr.ts +20 -19
- package/src/category/i18n/zh.ts +58 -57
- package/src/layouts/AstronomyCategoryHome.astro +224 -0
- package/src/layouts/ProductionCategoryPage.astro +81 -24
- package/src/layouts/ProductionUtilityPage.astro +146 -237
- package/src/layouts/production-utility-page.css +248 -0
- package/src/mfe/category-ui.ts +22 -15
- package/src/pages/[locale]/[utilities]/[categories]/[category].astro +2 -2
- package/src/pages/utilidades/categorias/[category].astro +2 -2
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
---
|
|
2
|
+
import { Icon } from "astro-icon/components";
|
|
3
|
+
import { SEORenderer } from "@jjlmoya/utils-shared";
|
|
4
|
+
import ProductionBreadcrumb from "../components/ProductionBreadcrumb.astro";
|
|
5
|
+
import ProductionPage from "./ProductionPage.astro";
|
|
6
|
+
import { getCategoryPath } from "../mfe/routes";
|
|
7
|
+
import { getCategoryUi } from "../mfe/category-ui";
|
|
8
|
+
import type { CategoryLocaleContent, KnownLocale } from "../types";
|
|
9
|
+
import "../category/astronomy-category-home.css";
|
|
10
|
+
|
|
11
|
+
interface CategoryTool {
|
|
12
|
+
id: string;
|
|
13
|
+
icon: string;
|
|
14
|
+
title: string;
|
|
15
|
+
description: string;
|
|
16
|
+
href: string;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
interface Props {
|
|
20
|
+
locale: KnownLocale;
|
|
21
|
+
category: CategoryLocaleContent;
|
|
22
|
+
tools: CategoryTool[];
|
|
23
|
+
alternates: { language: KnownLocale; url: string }[];
|
|
24
|
+
image?: string | undefined;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const { locale, category, tools, alternates, image } = Astro.props;
|
|
28
|
+
const publicPath = getCategoryPath(locale, category.slug);
|
|
29
|
+
const ui = getCategoryUi(locale);
|
|
30
|
+
const firstTool = tools[0];
|
|
31
|
+
const constellationTools = tools;
|
|
32
|
+
const getToolPointSize = (count: number): string => {
|
|
33
|
+
if (count > 500) return "0.28rem";
|
|
34
|
+
if (count > 80) return "0.4rem";
|
|
35
|
+
return "0.72rem";
|
|
36
|
+
};
|
|
37
|
+
const toolPointSize = getToolPointSize(tools.length);
|
|
38
|
+
const getStarSize = (index: number): string => {
|
|
39
|
+
if (index % 11 === 0) return "0.28rem";
|
|
40
|
+
if (index % 4 === 0) return "0.16rem";
|
|
41
|
+
return "0.1rem";
|
|
42
|
+
};
|
|
43
|
+
const getStarOpacity = (index: number): string => {
|
|
44
|
+
if (index % 7 === 0) return "0.95";
|
|
45
|
+
if (index % 3 === 0) return "0.65";
|
|
46
|
+
return "0.38";
|
|
47
|
+
};
|
|
48
|
+
const stars = Array.from({ length: 72 }, (_, index) => ({
|
|
49
|
+
left: `${((index * 47) % 97) + 1}%`,
|
|
50
|
+
top: `${((index * 61) % 91) + 3}%`,
|
|
51
|
+
size: getStarSize(index),
|
|
52
|
+
opacity: getStarOpacity(index),
|
|
53
|
+
delay: `${index % 9}`,
|
|
54
|
+
}));
|
|
55
|
+
const getConstellationSide = (left: number, top: number): "left" | "right" | "bottom" | "top" => {
|
|
56
|
+
if (left > 62) return "right";
|
|
57
|
+
if (left < 38) return "left";
|
|
58
|
+
return top > 50 ? "bottom" : "top";
|
|
59
|
+
};
|
|
60
|
+
const handPlacedPositions = [
|
|
61
|
+
[55, 12],
|
|
62
|
+
[80, 28],
|
|
63
|
+
[88, 57],
|
|
64
|
+
[69, 81],
|
|
65
|
+
[43, 91],
|
|
66
|
+
[17, 73],
|
|
67
|
+
[11, 43],
|
|
68
|
+
[30, 20],
|
|
69
|
+
[63, 24],
|
|
70
|
+
[83, 73],
|
|
71
|
+
[25, 57],
|
|
72
|
+
[39, 11],
|
|
73
|
+
] as const;
|
|
74
|
+
const constellationPositions = constellationTools.map((_, index) => {
|
|
75
|
+
const count = Math.max(constellationTools.length, 1);
|
|
76
|
+
const handPlaced = handPlacedPositions[index];
|
|
77
|
+
const drift = ((index * 17) % 13) - 6;
|
|
78
|
+
const angle = index * 2.399963 + drift * 0.025;
|
|
79
|
+
const radius = 12 + Math.sqrt((index + 0.5) / count) * 34 + drift * 0.25;
|
|
80
|
+
const left = handPlaced?.[0] ?? 50 + Math.cos(angle) * radius;
|
|
81
|
+
const top = handPlaced?.[1] ?? 50 + Math.sin(angle) * radius;
|
|
82
|
+
return {
|
|
83
|
+
left: `${left.toFixed(2)}%`,
|
|
84
|
+
top: `${top.toFixed(2)}%`,
|
|
85
|
+
side: getConstellationSide(left, top),
|
|
86
|
+
};
|
|
87
|
+
});
|
|
88
|
+
---
|
|
89
|
+
|
|
90
|
+
<ProductionPage
|
|
91
|
+
title={category.title}
|
|
92
|
+
description={category.description}
|
|
93
|
+
{locale}
|
|
94
|
+
{publicPath}
|
|
95
|
+
{alternates}
|
|
96
|
+
{image}
|
|
97
|
+
>
|
|
98
|
+
<div class="astronomy-home" data-astronomy-home>
|
|
99
|
+
<div class="astronomy-page-stars" aria-hidden="true">
|
|
100
|
+
{stars.slice(0, 42).map((star) => (
|
|
101
|
+
<i
|
|
102
|
+
class="astronomy-page-star"
|
|
103
|
+
style={`--star-left: ${star.left}; --star-top: ${star.top}; --star-size: ${star.size}; --star-opacity: ${star.opacity}; --star-delay: ${star.delay}s;`}
|
|
104
|
+
></i>
|
|
105
|
+
))}
|
|
106
|
+
</div>
|
|
107
|
+
<div class="astronomy-shell">
|
|
108
|
+
<ProductionBreadcrumb locale={locale} currentTitle={category.title} />
|
|
109
|
+
|
|
110
|
+
<section class="astronomy-orbit" aria-labelledby="astronomy-title">
|
|
111
|
+
<div id="astronomy-sky" class:list={["astronomy-sky", tools.length > 12 && "astronomy-sky-dense"]} aria-label={category.title}>
|
|
112
|
+
<div class="astronomy-sky-stars" aria-hidden="true">
|
|
113
|
+
{stars.map((star) => (
|
|
114
|
+
<i
|
|
115
|
+
class="astronomy-star"
|
|
116
|
+
style={`--star-left: ${star.left}; --star-top: ${star.top}; --star-size: ${star.size}; --star-opacity: ${star.opacity}; --star-delay: ${star.delay}s;`}
|
|
117
|
+
></i>
|
|
118
|
+
))}
|
|
119
|
+
</div>
|
|
120
|
+
<div class="astronomy-sky-dust" aria-hidden="true"></div>
|
|
121
|
+
<div class="astronomy-sky-coordinates" aria-hidden="true">
|
|
122
|
+
<span>α 05h 55m 10s</span>
|
|
123
|
+
<span>δ +07° 24′ 25″</span>
|
|
124
|
+
</div>
|
|
125
|
+
<div class="astronomy-celestial-scene" aria-hidden="true">
|
|
126
|
+
<div class="astronomy-orbit-track astronomy-orbit-track-one"><span class="astronomy-orbit-body astronomy-orbit-body-one"></span></div>
|
|
127
|
+
<div class="astronomy-orbit-track astronomy-orbit-track-two"><span class="astronomy-orbit-body astronomy-orbit-body-two"></span></div>
|
|
128
|
+
<div class="astronomy-orbit-track astronomy-orbit-track-three"><span class="astronomy-orbit-body astronomy-orbit-body-three"></span></div>
|
|
129
|
+
<div class="astronomy-planet"><span></span></div>
|
|
130
|
+
</div>
|
|
131
|
+
<div class="astronomy-constellation-center" aria-hidden="true">
|
|
132
|
+
<span>ASTRONOMIA</span>
|
|
133
|
+
<b>*</b>
|
|
134
|
+
</div>
|
|
135
|
+
|
|
136
|
+
{constellationTools.map((tool, index) => (
|
|
137
|
+
<a
|
|
138
|
+
class:list={["astronomy-star-link", `astronomy-star-link-${constellationPositions[index]?.side ?? "top"}`]}
|
|
139
|
+
href={tool.href}
|
|
140
|
+
data-tool-node
|
|
141
|
+
data-tool-index={index}
|
|
142
|
+
style={`--node-left: ${constellationPositions[index]?.left}; --node-top: ${constellationPositions[index]?.top}; --node-size: ${toolPointSize};`}
|
|
143
|
+
aria-label={`${tool.title}: ${ui.openTool}`}
|
|
144
|
+
>
|
|
145
|
+
<span class="astronomy-star-link-point" aria-hidden="true"></span>
|
|
146
|
+
<span class="astronomy-star-link-label">
|
|
147
|
+
<span class="astronomy-star-link-icon" aria-hidden="true"><Icon name={tool.icon} /></span>
|
|
148
|
+
<b>{String(index + 1).padStart(2, "0")}</b>
|
|
149
|
+
<strong>{tool.title}</strong>
|
|
150
|
+
<small>{tool.description}</small>
|
|
151
|
+
</span>
|
|
152
|
+
</a>
|
|
153
|
+
))}
|
|
154
|
+
|
|
155
|
+
<p class="astronomy-sky-caption">{String(tools.length).padStart(2, "0")} {ui.catalogLabel}</p>
|
|
156
|
+
</div>
|
|
157
|
+
|
|
158
|
+
<div class="astronomy-editorial">
|
|
159
|
+
<p class="astronomy-overline">{ui.observationEyebrow}</p>
|
|
160
|
+
<h1 id="astronomy-title">{category.title}</h1>
|
|
161
|
+
<p class="astronomy-lede">{category.description}</p>
|
|
162
|
+
|
|
163
|
+
{firstTool && (
|
|
164
|
+
<div class="astronomy-observation" data-mission-panel>
|
|
165
|
+
<div class="astronomy-observation-heading">
|
|
166
|
+
<span class="astronomy-observation-dot" aria-hidden="true"></span>
|
|
167
|
+
<p>{ui.missionLabel}</p>
|
|
168
|
+
</div>
|
|
169
|
+
<h2 data-mission-title>{firstTool.title}</h2>
|
|
170
|
+
<p data-mission-description>{firstTool.description}</p>
|
|
171
|
+
<div class="astronomy-observation-actions">
|
|
172
|
+
<button type="button" data-route-button aria-controls="astronomy-sky">
|
|
173
|
+
{ui.exploreRoute}<span aria-hidden="true">↗</span>
|
|
174
|
+
</button>
|
|
175
|
+
<a data-mission-link href={firstTool.href}>
|
|
176
|
+
{ui.openTool}<span aria-hidden="true">→</span>
|
|
177
|
+
</a>
|
|
178
|
+
</div>
|
|
179
|
+
<p class="astronomy-observation-status" aria-live="polite" data-mission-status>
|
|
180
|
+
{firstTool.title}
|
|
181
|
+
</p>
|
|
182
|
+
</div>
|
|
183
|
+
)}
|
|
184
|
+
|
|
185
|
+
<nav class="astronomy-tool-index" aria-label={category.title}>
|
|
186
|
+
<details open={tools.length <= 12}>
|
|
187
|
+
<summary class="astronomy-tool-index-title">
|
|
188
|
+
<span>{ui.toolIndexLabel}</span>
|
|
189
|
+
<span>{String(tools.length).padStart(2, "0")}</span>
|
|
190
|
+
</summary>
|
|
191
|
+
<ol>
|
|
192
|
+
{tools.map((tool, index) => (
|
|
193
|
+
<li>
|
|
194
|
+
<a href={tool.href} data-tool-index-link data-tool-index={index}>
|
|
195
|
+
<span>{String(index + 1).padStart(2, "0")}</span>
|
|
196
|
+
<strong>{tool.title}</strong>
|
|
197
|
+
<i aria-hidden="true">↗</i>
|
|
198
|
+
</a>
|
|
199
|
+
</li>
|
|
200
|
+
))}
|
|
201
|
+
</ol>
|
|
202
|
+
</details>
|
|
203
|
+
</nav>
|
|
204
|
+
</div>
|
|
205
|
+
</section>
|
|
206
|
+
|
|
207
|
+
<section class="astronomy-field-notes" aria-labelledby="astronomy-notes-title">
|
|
208
|
+
<div class="astronomy-field-notes-title">
|
|
209
|
+
<span class="astronomy-overline">{ui.fieldNotesLabel}</span>
|
|
210
|
+
<h2 id="astronomy-notes-title">{ui.fieldNotesTitle}</h2>
|
|
211
|
+
</div>
|
|
212
|
+
<div class="astronomy-seo">
|
|
213
|
+
<SEORenderer content={{ locale, sections: category.seo }} />
|
|
214
|
+
</div>
|
|
215
|
+
</section>
|
|
216
|
+
</div>
|
|
217
|
+
</div>
|
|
218
|
+
</ProductionPage>
|
|
219
|
+
|
|
220
|
+
<script>
|
|
221
|
+
import { enhanceAstronomyHome } from "../category/astronomy-category-home";
|
|
222
|
+
|
|
223
|
+
enhanceAstronomyHome();
|
|
224
|
+
</script>
|
|
@@ -7,14 +7,33 @@ import type { KnownLocale, CategoryLocaleContent } from "../types";
|
|
|
7
7
|
import { getCategoryPath } from "../mfe/routes";
|
|
8
8
|
import { getCategoryUi } from "../mfe/category-ui";
|
|
9
9
|
|
|
10
|
-
interface CategoryTool {
|
|
11
|
-
|
|
10
|
+
interface CategoryTool {
|
|
11
|
+
id: string;
|
|
12
|
+
icon: string;
|
|
13
|
+
title: string;
|
|
14
|
+
description: string;
|
|
15
|
+
href: string;
|
|
16
|
+
}
|
|
17
|
+
interface Props {
|
|
18
|
+
locale: KnownLocale;
|
|
19
|
+
category: CategoryLocaleContent;
|
|
20
|
+
tools: CategoryTool[];
|
|
21
|
+
alternates: { language: KnownLocale; url: string }[];
|
|
22
|
+
image?: string | undefined;
|
|
23
|
+
}
|
|
12
24
|
const { locale, category, tools, alternates, image } = Astro.props;
|
|
13
25
|
const publicPath = getCategoryPath(locale, category.slug);
|
|
14
26
|
const ui = getCategoryUi(locale);
|
|
15
27
|
---
|
|
16
28
|
|
|
17
|
-
<ProductionPage
|
|
29
|
+
<ProductionPage
|
|
30
|
+
title={category.title}
|
|
31
|
+
description={category.description}
|
|
32
|
+
{locale}
|
|
33
|
+
{publicPath}
|
|
34
|
+
{alternates}
|
|
35
|
+
{image}
|
|
36
|
+
>
|
|
18
37
|
<div class="category-production">
|
|
19
38
|
<div class="category-production-inner">
|
|
20
39
|
<ProductionBreadcrumb locale={locale} currentTitle={category.title} />
|
|
@@ -22,16 +41,29 @@ const ui = getCategoryUi(locale);
|
|
|
22
41
|
<h1>{category.title}</h1><p>{category.description}</p>
|
|
23
42
|
</header>
|
|
24
43
|
<div class="category-tools-grid">
|
|
25
|
-
{
|
|
26
|
-
|
|
27
|
-
<
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
44
|
+
{
|
|
45
|
+
tools.map((tool, index) => (
|
|
46
|
+
<a href={tool.href} class="category-tool-card">
|
|
47
|
+
<span class="category-tool-index">
|
|
48
|
+
{String(index + 1).padStart(2, "0")}
|
|
49
|
+
</span>
|
|
50
|
+
<div class="category-tool-icon">
|
|
51
|
+
<Icon name={tool.icon} />
|
|
52
|
+
</div>
|
|
53
|
+
<>
|
|
54
|
+
<h2>{tool.title}</h2>
|
|
55
|
+
<p>{tool.description}</p>
|
|
56
|
+
</>
|
|
57
|
+
<span class="category-tool-cta">
|
|
58
|
+
{ui.useTool} <span aria-hidden="true">→</span>
|
|
59
|
+
</span>
|
|
60
|
+
</a>
|
|
61
|
+
))
|
|
62
|
+
}
|
|
33
63
|
</div>
|
|
34
|
-
<section class="category-seo-production"
|
|
64
|
+
<section class="category-seo-production">
|
|
65
|
+
<SEORenderer content={{ locale, sections: category.seo }} />
|
|
66
|
+
</section>
|
|
35
67
|
</div>
|
|
36
68
|
</div>
|
|
37
69
|
</ProductionPage>
|
|
@@ -40,7 +72,12 @@ const ui = getCategoryUi(locale);
|
|
|
40
72
|
.category-production {
|
|
41
73
|
min-height: 100vh;
|
|
42
74
|
overflow-x: clip;
|
|
43
|
-
background: radial-gradient(
|
|
75
|
+
background: radial-gradient(
|
|
76
|
+
ellipse at top,
|
|
77
|
+
var(--primary-10),
|
|
78
|
+
var(--bg-surface) 50%,
|
|
79
|
+
var(--bg-main)
|
|
80
|
+
);
|
|
44
81
|
}
|
|
45
82
|
|
|
46
83
|
.category-production-inner {
|
|
@@ -86,24 +123,35 @@ const ui = getCategoryUi(locale);
|
|
|
86
123
|
min-height: 230px;
|
|
87
124
|
flex-direction: column;
|
|
88
125
|
padding: var(--space-lg);
|
|
89
|
-
border: 1px solid
|
|
126
|
+
border: 1px solid
|
|
127
|
+
color-mix(in srgb, var(--astronomy-accent) 18%, var(--border-base));
|
|
90
128
|
border-radius: 1.25rem;
|
|
91
|
-
background: linear-gradient(
|
|
129
|
+
background: linear-gradient(
|
|
130
|
+
145deg,
|
|
131
|
+
var(--bg-surface),
|
|
132
|
+
color-mix(in srgb, var(--astronomy-accent) 4%, var(--bg-surface))
|
|
133
|
+
);
|
|
92
134
|
color: inherit;
|
|
93
135
|
text-decoration: none;
|
|
94
|
-
box-shadow: 0 1rem 2rem
|
|
95
|
-
|
|
136
|
+
box-shadow: 0 1rem 2rem
|
|
137
|
+
color-mix(in srgb, var(--shadow-base, #000) 35%, transparent);
|
|
138
|
+
transition:
|
|
139
|
+
transform 0.25s ease,
|
|
140
|
+
border-color 0.25s ease,
|
|
141
|
+
box-shadow 0.25s ease;
|
|
96
142
|
}
|
|
97
143
|
|
|
98
144
|
.category-tool-card:hover,
|
|
99
145
|
.category-tool-card:focus-visible {
|
|
100
146
|
border-color: var(--astronomy-accent);
|
|
101
|
-
box-shadow: 0 1.25rem 2.5rem
|
|
147
|
+
box-shadow: 0 1.25rem 2.5rem
|
|
148
|
+
color-mix(in srgb, var(--astronomy-accent) 18%, transparent);
|
|
102
149
|
transform: translateY(-4px);
|
|
103
150
|
}
|
|
104
151
|
|
|
105
152
|
.category-tool-card:focus-visible {
|
|
106
|
-
outline: 3px solid
|
|
153
|
+
outline: 3px solid
|
|
154
|
+
color-mix(in srgb, var(--astronomy-accent) 55%, transparent);
|
|
107
155
|
outline-offset: 4px;
|
|
108
156
|
}
|
|
109
157
|
|
|
@@ -127,9 +175,14 @@ const ui = getCategoryUi(locale);
|
|
|
127
175
|
height: 3.25rem;
|
|
128
176
|
place-items: center;
|
|
129
177
|
margin-bottom: var(--space-md);
|
|
130
|
-
border: 1px solid
|
|
178
|
+
border: 1px solid
|
|
179
|
+
color-mix(in srgb, var(--astronomy-accent) 28%, transparent);
|
|
131
180
|
border-radius: 1rem;
|
|
132
|
-
background: color-mix(
|
|
181
|
+
background: color-mix(
|
|
182
|
+
in srgb,
|
|
183
|
+
var(--astronomy-accent) 12%,
|
|
184
|
+
var(--bg-surface)
|
|
185
|
+
);
|
|
133
186
|
color: var(--astronomy-accent);
|
|
134
187
|
font-size: 1.6rem;
|
|
135
188
|
}
|
|
@@ -139,7 +192,6 @@ const ui = getCategoryUi(locale);
|
|
|
139
192
|
top: var(--space-md);
|
|
140
193
|
right: var(--space-lg);
|
|
141
194
|
color: var(--text-dimmed, var(--text-muted));
|
|
142
|
-
font-family: ui-monospace, SFMono-Regular, monospace;
|
|
143
195
|
font-size: 0.72rem;
|
|
144
196
|
letter-spacing: 0.12em;
|
|
145
197
|
}
|
|
@@ -178,7 +230,12 @@ const ui = getCategoryUi(locale);
|
|
|
178
230
|
}
|
|
179
231
|
|
|
180
232
|
@media (width <= 768px) {
|
|
181
|
-
.category-production-inner {
|
|
182
|
-
|
|
233
|
+
.category-production-inner {
|
|
234
|
+
padding: var(--space-lg) var(--space-sm) var(--space-3xl);
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
.category-tools-grid {
|
|
238
|
+
grid-template-columns: 1fr;
|
|
239
|
+
}
|
|
183
240
|
}
|
|
184
241
|
</style>
|