Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
342 changes: 153 additions & 189 deletions package-lock.json

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions projects/element-ng/tsconfig.lib.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
"outDir": "../../out-tsc/lib",
"declaration": true,
"inlineSources": true,
"ignoreDeprecations": "5.0",
"types": ["@siemens/element-translate-ng/localize-types"]
},
"angularCompilerOptions": {
Expand Down
1 change: 1 addition & 0 deletions projects/element-ng/tsconfig.schematics.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
"extends": "../../tsconfig.json",
"compilerOptions": {
"baseUrl": ".",
"ignoreDeprecations": "5.0",
"moduleResolution": "node",
"noEmitOnError": true,
"rootDir": "schematics",
Expand Down
1 change: 1 addition & 0 deletions projects/element-ng/weather-widget/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './public-api';
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
<!-- Today section -->
<div class="weather-today">
<div class="weather-today-temp">
<span class="weather-temp-display">{{ todaysTemp() }}</span>
</div>
<div class="weather-today-details">
<!-- Today icon: custom template > iconUrl > icon font -->
@if (todayIconTemplate()) {
<ng-container *ngTemplateOutlet="todayIconTemplate()!" />
} @else if (todaysIconUrl()) {
<img class="weather-today-icon-img" [src]="todaysIconUrl()" [alt]="todaysWeather()" />
} @else if (todaysIcon()) {
<si-icon class="weather-today-icon" [icon]="todaysIcon()!" />
}
<span class="weather-today-description">{{ todaysWeather() }}</span>
@if (showMinMax()) {
<div class="weather-minmax">
<span class="text-secondary">{{ minTemp() }}</span>
<span class="fw-bold">{{ maxTemp() }}</span>
</div>
}
</div>
</div>

<!-- Additional data -->
@if (showAdditionalData()) {
<div class="weather-additional">
<div class="weather-additional-row">
<span class="text-secondary">Precip</span>
<span class="fw-bold">{{ additionalData().precip }}</span>
</div>
<div class="weather-additional-row">
<span class="text-secondary">Wind</span>
<span class="fw-bold">{{ additionalData().wind }}</span>
</div>
<div class="weather-additional-row">
<span class="text-secondary">UVI</span>
<span class="fw-bold">{{ additionalData().uvi }} {{ additionalData().uviLabel }}</span>
</div>
<div class="weather-additional-row">
<span class="text-secondary">Feels Like</span>
<span class="fw-bold">{{ additionalData().feelsLike }}</span>
</div>
</div>
}

<!-- Forecast -->
@if (showForecast() && forecast().length > 0) {
@if (layout() === 'vertical') {
<div class="weather-forecast-table">
@for (day of forecast(); track day.day; let i = $index) {
<div class="weather-forecast-row">
<span class="weather-forecast-day text-secondary">{{ day.day }}</span>
<!-- Forecast icon: custom template > iconUrl > icon font -->
<div class="weather-forecast-icon-cell">
@if (forecastIconTemplate()) {
<ng-container *ngTemplateOutlet="forecastIconTemplate()!; context: { $implicit: day }" />
} @else if (day.iconUrl) {
<img class="weather-forecast-icon-img" [src]="day.iconUrl" [alt]="day.day" />
} @else if (day.icon) {
<si-icon class="weather-forecast-icon" [icon]="day.icon" />
}
</div>
@for (col of forecastColumns(); track col.icon; let colIdx = $index) {
<div class="weather-forecast-cell" [class.weather-forecast-col-1]="colIdx === 0" [class.weather-forecast-col-2]="colIdx === 1">
<si-icon class="weather-forecast-meta-icon" [icon]="col.icon" />
<span>{{ col.values[i] }}</span>
</div>
}
<div class="weather-minmax weather-minmax--sm">
<span class="text-secondary">{{ day.minTemp }}</span>
<span class="fw-bold">{{ day.maxTemp }}</span>
</div>
</div>
}
</div>
} @else {
<div class="weather-forecast-columns">
@for (day of forecast(); track day.day; let i = $index) {
<div class="weather-forecast-col" [attr.data-col-index]="i">
<span class="weather-forecast-day text-secondary">{{ day.day }}</span>
<!-- Forecast icon: custom template > iconUrl > icon font -->
@if (forecastIconTemplate()) {
<ng-container *ngTemplateOutlet="forecastIconTemplate()!; context: { $implicit: day }" />
} @else if (day.iconUrl) {
<img class="weather-forecast-col-icon-img" [src]="day.iconUrl" [alt]="day.day" />
} @else if (day.icon) {
<si-icon class="weather-forecast-col-icon" [icon]="day.icon" />
}
<div class="weather-minmax">
<span class="text-secondary">{{ day.minTemp }}</span>
<span class="fw-bold">{{ day.maxTemp }}</span>
</div>
</div>
}
</div>
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,241 @@
@use '@siemens/element-theme/src/styles/variables';
@use 'sass:map';

:host {
display: flex;
flex-direction: column;
padding: map.get(variables.$spacers, 6);
container-type: inline-size;
}

// --- Sections use spacing-9 (32px) gap between them ---

.weather-additional {
margin-block-start: map.get(variables.$spacers, 9);
}

.weather-forecast-table {
margin-block-start: map.get(variables.$spacers, 9);
}

.weather-forecast-columns {
margin-block-start: map.get(variables.$spacers, 9);
}

// --- Today header ---

.weather-today {
display: flex;
align-items: flex-start;
justify-content: space-between;
}

.weather-temp-display {
font-family: var(--element-font-family-display);
font-size: var(--element-font-size-display-xl, 56px);
line-height: var(--element-font-line-height-display-1, 72px);
font-weight: 400;
}

.weather-today-details {
display: flex;
flex-direction: column;
align-items: flex-end;
gap: 4px;
}

.weather-today-icon {
font-size: 40px;
}

.weather-today-icon-img {
width: 40px;
height: 40px;
object-fit: contain;
}

.weather-today-description {
font-size: 16px;
line-height: 20px;
text-align: end;
}

.weather-minmax {
display: flex;
gap: 4px;
font-size: 16px;
line-height: 20px;
}

.weather-minmax--sm {
font-size: 14px;
line-height: 16px;
}

// --- Additional data ---

.weather-additional {
display: flex;
flex-direction: column;
gap: map.get(variables.$spacers, 4);
}

.weather-additional-row {
display: flex;
justify-content: space-between;
align-items: flex-start;
font-size: 14px;
line-height: 16px;
text-align: end;
}

// --- Vertical forecast table ---

.weather-forecast-table {
display: flex;
flex-direction: column;
gap: map.get(variables.$spacers, 4);
}

.weather-forecast-row {
display: flex;
align-items: center;
gap: map.get(variables.$spacers, 6);
height: 32px;
}

// Fixed columns
.weather-forecast-day {
flex: 0 0 44px;
font-size: 14px;
line-height: 16px;
white-space: nowrap;
}

.weather-forecast-icon-cell {
flex: 0 0 20px;
display: flex;
align-items: center;
justify-content: center;
}

.weather-forecast-icon {
font-size: 20px;
}

.weather-forecast-icon-img {
width: 20px;
height: 20px;
object-fit: contain;
}

// Flexible columns — expand evenly
.weather-forecast-cell {
display: flex;
align-items: center;
gap: map.get(variables.$spacers, 1);
flex: 1 1 0;
min-width: 0;
justify-content: flex-end;
font-size: 14px;
line-height: 16px;
}

.weather-forecast-meta-icon {
font-size: 16px;
color: var(--element-text-secondary);
}

.weather-forecast-row .weather-minmax {
flex: 1 1 0;
min-width: 0;
justify-content: flex-end;
}

// --- Horizontal forecast columns ---

.weather-forecast-columns {
display: flex;
}

.weather-forecast-col {
display: flex;
flex-direction: column;
align-items: center;
gap: map.get(variables.$spacers, 4);
flex: 1 1 0;
min-width: 0;
padding-block: map.get(variables.$spacers, 2);
}

.weather-forecast-col .weather-forecast-day {
width: auto;
text-align: center;
}

.weather-forecast-col-icon {
font-size: 24px;
}

.weather-forecast-col-icon-img {
width: 24px;
height: 24px;
object-fit: contain;
}

.weather-forecast-col .weather-minmax {
justify-content: center;
}

// --- Responsive: container queries ---
// Vertical: hide optional data columns, keep day + icon + temp
// Horizontal: hide day columns from end, keep icon + temp per column

// Vertical: below 280px hide first optional column
@container (max-width: 280px) {
.weather-forecast-col-1 {
display: none;
}
}

// Vertical: below 220px hide all optional columns
@container (max-width: 220px) {
.weather-forecast-col-1,
.weather-forecast-col-2 {
display: none;
}
}

// Vertical: below 160px hide forecast icon too
@container (max-width: 160px) {
.weather-forecast-col-1,
.weather-forecast-col-2 {
display: none;
}

.weather-forecast-icon-cell {
display: none;
}
}

// Horizontal: progressively hide day columns from the end
@container (max-width: 340px) {
.weather-forecast-col[data-col-index="4"] {
display: none;
}
}

@container (max-width: 280px) {
.weather-forecast-col[data-col-index="3"],
.weather-forecast-col[data-col-index="4"] {
display: none;
}
}

@container (max-width: 220px) {
.weather-forecast-col[data-col-index="2"],
.weather-forecast-col[data-col-index="3"],
.weather-forecast-col[data-col-index="4"] {
display: none;
}
}
Loading
Loading