Skip to content

Commit cb3e58b

Browse files
authored
feat(ui): core components created/updated for startv2 page auto creation from core | Issue #63 (#197)
2 parents 2760025 + 5fedfbf commit cb3e58b

File tree

71 files changed

+20626
-85
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

71 files changed

+20626
-85
lines changed

.github/workflows/ci.yml

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,9 +40,19 @@ jobs:
4040
- name: Nix cache
4141
uses: DeterminateSystems/flakehub-cache-action@main
4242

43+
- name: Set up Python
44+
uses: actions/setup-python@v4
45+
with:
46+
python-version: "3.11" # match your local python
47+
48+
- name: Install dependencies
49+
run: |
50+
python -m pip install --upgrade pip
51+
pip install pre-commit
52+
4353
- name: Run linters via pre-commit
4454
id: linter
45-
run: nix develop -c pre-commit run --all-files
55+
run: pre-commit run --all-files
4656

4757
test:
4858
runs-on: ubuntu-24.04

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ node_modules/
3131
# Various other things
3232
.direnv
3333
.npmrc
34-
.pre-commit-config.yaml
34+
# .pre-commit-config.yaml
3535
.wrangler
3636
CHANGES.md
3737

.pre-commit-config.yaml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
repos:
2+
- repo: https://github.com/pre-commit/mirrors-eslint
3+
rev: v9.39.0 # your ESLint version
4+
hooks:
5+
- id: eslint
6+
args: ["--ext", ".ts,.tsx,.js,.jsx"]

core/src/index.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,8 @@ export * from './lib/shell';
33
export * from './lib/message-toast';
44
export * from './lib/config';
55
export * from './lib/feature-detail';
6-
export * from './lib/models/feature-detail.model';
6+
export * from './lib/news';
7+
export * from './lib/models';
8+
export * from './lib/footer';
9+
export * from './lib/search';
10+
export * from './lib/jokes';
Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1-
<p-card class="garuda-card-p-card">
2-
@switch (cardRole()) {
3-
@case ('product-showcase') {
1+
@switch (cardRole()) {
2+
@case ('product-showcase') {
3+
<!-- ✅ Big variant uses p-card fully -->
4+
<p-card class="garuda-card-product-showcase">
45
<ng-template #header>
56
<div class="garuda-card-product-showcase-header">
67
<div class="garuda-card-thumbnail-container">
@@ -12,12 +13,34 @@
1213
</div>
1314
</div>
1415
</ng-template>
16+
1517
<ng-content></ng-content>
18+
1619
<ng-template #footer>
1720
<div class="garuda-card-action-container">
1821
<ng-content select="[garudaCardAction]"></ng-content>
1922
</div>
2023
</ng-template>
21-
}
24+
</p-card>
2225
}
23-
</p-card>
26+
27+
@case ('product-showcase-small') {
28+
<div
29+
class="garuda-card-product-showcase-small"
30+
(click)="navigate()"
31+
(keyup.enter)="navigate()"
32+
(keyup.space)="navigate()"
33+
role="button"
34+
tabindex="0"
35+
>
36+
<div class="garuda-card-product-showcase-header-small">
37+
<div class="garuda-card-title-small">
38+
<ng-content select="[garudaCardTitleWrapper]"></ng-content>
39+
</div>
40+
<div class="garuda-card-thumbnail-container-small">
41+
<ng-content select="[garudaCardThumbnailWrapper]"></ng-content>
42+
</div>
43+
</div>
44+
</div>
45+
}
46+
}

core/src/lib/card/card.component.scss

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,3 +30,26 @@
3030
justify-content: space-evenly;
3131
}
3232
}
33+
34+
.garuda-card-product-showcase-small {
35+
border: 2px solid transparent;
36+
border-radius: 8px;
37+
display: flex;
38+
justify-content: space-between;
39+
align-items: center;
40+
width: 160px;
41+
height: 160px;
42+
margin: 10px;
43+
padding: 1rem;
44+
}
45+
.garuda-card-thumbnail-container-small {
46+
display: flex;
47+
justify-content: center;
48+
align-items: center;
49+
// margin-top: -25px;
50+
}
51+
52+
.garuda-card-product-showcase-small:hover {
53+
//border: 2px solid var(--p-text-color);
54+
transform: scale(1.2);
55+
}
Lines changed: 31 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,53 +1,50 @@
1-
import {
2-
Component,
3-
computed,
4-
EventEmitter,
5-
HostBinding,
6-
inject,
7-
Input,
8-
input,
9-
Output,
10-
ElementRef,
11-
Renderer2,
12-
AfterViewInit,
13-
OnDestroy,
14-
} from '@angular/core';
1+
import { Component, HostBinding, inject, input, ElementRef, Renderer2, AfterViewInit, OnDestroy, output } from '@angular/core';
152
import { CommonModule } from '@angular/common';
163
import { Card } from 'primeng/card';
17-
import { FeatureData } from '../models/feature-detail.model';
18-
import { FeatureDetailPopupService } from '../feature-detail/services/feature-detail-popup-service';
4+
import { FeatureData } from '../models/feature-detail/feature-detail.model';
5+
import { PopupService } from '../services/popup/popup.service';
6+
import { FeatureDetailComponent } from '../feature-detail/feature-detail.component';
197

20-
export type RoleType = 'product-showcase';
8+
export type RoleType = 'product-showcase' | 'product-showcase-small';
219

2210
@Component({
2311
selector: 'garuda-card',
12+
standalone: true,
2413
imports: [CommonModule, Card],
2514
templateUrl: './card.component.html',
26-
styleUrl: './card.component.scss',
15+
styleUrls: ['./card.component.scss'],
2716
host: {
2817
class: 'garuda-card',
2918
},
3019
})
3120
export class CardComponent implements AfterViewInit, OnDestroy {
3221
cardRole = input.required<RoleType>();
33-
@Input() feature?: FeatureData;
34-
@Input() actionFeatures?: Record<string, FeatureData> = {};
35-
@Output() actionClicked: EventEmitter<string> = new EventEmitter<string>();
22+
link = input<string | undefined>('');
23+
feature = input<FeatureData>();
24+
actionFeatures = input<Record<string, FeatureData>>({});
25+
actionClicked = output<string>();
3626

37-
private featureDetailPopupService = inject(FeatureDetailPopupService);
27+
private popupService = inject(PopupService);
3828
private el = inject(ElementRef<HTMLElement>);
3929
private renderer = inject(Renderer2);
4030
private removeClickListener?: () => void;
4131

4232
@HostBinding('class.garuda-card__product-showcase')
43-
private productShowcaseClass = computed(() => this.cardRole() === 'product-showcase');
33+
get isProductShowcase(): boolean {
34+
return this.cardRole() === 'product-showcase';
35+
}
36+
37+
@HostBinding('class.garuda-card__product-showcase-small')
38+
get isProductShowcaseSmall(): boolean {
39+
return this.cardRole() === 'product-showcase-small';
40+
}
4441

4542
ngAfterViewInit(): void {
46-
//data-action
4743
this.removeClickListener = this.renderer.listen(this.el.nativeElement, 'click', (event: Event) => {
4844
const target = event.target as HTMLElement;
4945
const actionElement = target.closest('[garudaCardAction], [data-action]') as HTMLElement | null;
5046
const action = actionElement?.dataset?.['action'];
47+
5148
if (action) {
5249
event.stopPropagation();
5350
this.openDetail(action);
@@ -61,9 +58,16 @@ export class CardComponent implements AfterViewInit, OnDestroy {
6158

6259
openDetail(action: string): void {
6360
this.actionClicked.emit(action);
64-
const featureData = this.actionFeatures?.[action] || this.feature;
65-
if (featureData) {
66-
this.featureDetailPopupService.open(featureData);
61+
62+
const featureData = this.actionFeatures()?.[action] || this.feature;
63+
if (!featureData) return;
64+
65+
this.popupService.open(FeatureDetailComponent, { data: { feature: featureData }, title: featureData?.title, showHeader: false });
66+
}
67+
68+
navigate() {
69+
if (this.link) {
70+
window.location.href = this.link() ?? '';
6771
}
6872
}
6973
}
Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
import { Directive, ElementRef, Input, OnInit, Renderer2, inject } from '@angular/core';
2-
import { FeatureCarouselSettings } from '../../models/feature-detail.model';
1+
import { Directive, ElementRef, Input, OnInit, Renderer2, inject, input } from '@angular/core';
2+
import { FeatureCarouselSettings } from '../../models/feature-detail/feature-detail.model';
33
import { Carousel } from 'primeng/carousel';
44

55
@Directive({
@@ -9,19 +9,21 @@ import { Carousel } from 'primeng/carousel';
99
export class FeatureDetailCarousel implements OnInit {
1010
private carousel = inject(Carousel);
1111

12-
@Input() featureScreenshots: string[] = [];
13-
@Input() carouselSettings?: FeatureCarouselSettings;
12+
featureScreenshots = input<string[]>([]);
13+
carouselSettings = input<FeatureCarouselSettings>();
1414

1515
ngOnInit(): void {
16-
if (this.carouselSettings) {
16+
if (this.carouselSettings()) {
1717
this.carousel.numVisible = 1;
1818
this.carousel.numScroll = 1;
19-
this.carousel.circular = !!this.carouselSettings.circularSlide;
19+
this.carousel.circular = !!this.carouselSettings()?.circularSlide;
2020
this.carousel.showIndicators = true;
2121
this.carousel.showNavigators = true;
22-
this.carousel.autoplayInterval = this.carouselSettings.autoPlayCarousel ? (this.carouselSettings.autoPlayIntervalDuration ?? 0) : 0;
22+
this.carousel.autoplayInterval = this.carouselSettings()?.autoPlayCarousel
23+
? (this.carouselSettings()?.autoPlayIntervalDuration ?? 0)
24+
: 0;
2325
}
2426

25-
this.carousel.value = this.featureScreenshots || [];
27+
this.carousel.value = this.featureScreenshots() || [];
2628
}
2729
}
Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Directive, ElementRef, Input, OnChanges, SimpleChanges, inject } from '@angular/core';
1+
import { Directive, ElementRef, OnChanges, SimpleChanges, inject, input } from '@angular/core';
22
import { DomSanitizer, SafeHtml } from '@angular/platform-browser';
33

44
@Directive({
@@ -9,14 +9,16 @@ export class FeatureDetailMoreinformation implements OnChanges {
99
private el = inject(ElementRef<HTMLElement>);
1010
private sanitizer = inject(DomSanitizer);
1111

12-
@Input('garudaFeatureDetailMoreinformation') htmlContent?: string;
12+
htmlContent = input<string | undefined>(undefined, {
13+
alias: 'garudaFeatureDetailMoreinformation',
14+
});
1315
ngOnChanges(changes: SimpleChanges): void {
14-
if (!this.htmlContent) return;
15-
if ('htmlContent' in changes && this.htmlContent) {
16-
// Sanitize HTML as string and assign
17-
const temp = document.createElement('div');
18-
temp.innerHTML = this.htmlContent;
19-
this.el.nativeElement.innerHTML = temp.innerHTML;
16+
const content = this.htmlContent();
17+
if (!content) {
18+
this.el.nativeElement.innerHTML = '';
19+
return;
2020
}
21+
const safeHtml: SafeHtml = this.sanitizer.bypassSecurityTrustHtml(content);
22+
this.el.nativeElement.innerHTML = this.sanitizer.sanitize(1, safeHtml) ?? '';
2123
}
2224
}

core/src/lib/feature-detail/directives/feature-detail-packages.ts

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Directive, Input, TemplateRef, ViewContainerRef, inject, OnChanges, SimpleChanges } from '@angular/core';
1+
import { Directive, input, TemplateRef, ViewContainerRef, inject, OnChanges, SimpleChanges } from '@angular/core';
22

33
@Directive({
44
selector: '[garudaFeatureDetailPackages]',
@@ -8,11 +8,15 @@ export class FeatureDetailPackages implements OnChanges {
88
private templateRef = inject(TemplateRef<any>);
99
private viewContainer = inject(ViewContainerRef);
1010

11-
@Input('garudaFeatureDetailPackages') packages: string[] | null = [];
11+
packages = input<string[] | null>([], {
12+
alias: 'garudaFeatureDetailPackages',
13+
});
14+
1215
ngOnChanges(changes: SimpleChanges): void {
1316
this.viewContainer.clear();
14-
if (this.packages && this.packages.length > 0) {
15-
for (const pkg of this.packages) {
17+
const packages = this.packages() ?? [];
18+
if (packages && packages?.length > 0) {
19+
for (const pkg of packages) {
1620
this.viewContainer.createEmbeddedView(this.templateRef, { $implicit: pkg });
1721
}
1822
}

0 commit comments

Comments
 (0)