mirror of https://github.com/ghostfolio/ghostfolio
committed by
GitHub
10 changed files with 366 additions and 178 deletions
@ -0,0 +1 @@ |
|||
export * from './logo-carousel.component'; |
@ -0,0 +1,7 @@ |
|||
export interface LogoItem { |
|||
className: string; |
|||
isMask?: boolean; |
|||
name: string; |
|||
title: string; |
|||
url: string; |
|||
} |
@ -0,0 +1,16 @@ |
|||
<div class="logo-carousel-container overflow-hidden position-relative w-100"> |
|||
<div class="align-items-center d-flex logo-carousel-track"> |
|||
@for (logo of logosRepeated; track $index) { |
|||
<div class="logo-carousel-item"> |
|||
<a |
|||
class="d-block logo" |
|||
target="_blank" |
|||
[attr.aria-label]="logo.name" |
|||
[class]="logo.className + (logo.isMask ? ' mask' : '')" |
|||
[href]="logo.url" |
|||
[title]="logo.title" |
|||
></a> |
|||
</div> |
|||
} |
|||
</div> |
|||
</div> |
@ -0,0 +1,213 @@ |
|||
:host { |
|||
display: block; |
|||
overflow: hidden; |
|||
position: relative; |
|||
width: 100%; |
|||
|
|||
.logo-carousel-container { |
|||
&::before, |
|||
&::after { |
|||
content: ''; |
|||
height: 100%; |
|||
pointer-events: none; |
|||
position: absolute; |
|||
top: 0; |
|||
width: 100px; |
|||
z-index: 2; |
|||
} |
|||
|
|||
&::before { |
|||
background: linear-gradient( |
|||
to right, |
|||
var(--light-background) 0%, |
|||
rgba(var(--palette-background-background), 0) 100% |
|||
); |
|||
left: 0; |
|||
} |
|||
|
|||
&::after { |
|||
background: linear-gradient( |
|||
to left, |
|||
var(--light-background) 0%, |
|||
rgba(var(--palette-background-background), 0) 100% |
|||
); |
|||
right: 0; |
|||
} |
|||
|
|||
@media (max-width: 768px) { |
|||
&::before, |
|||
&::after { |
|||
width: 50px; |
|||
} |
|||
} |
|||
|
|||
@media (max-width: 576px) { |
|||
&::before, |
|||
&::after { |
|||
width: 30px; |
|||
} |
|||
} |
|||
|
|||
.logo-carousel-track { |
|||
animation: scroll 60s linear infinite; |
|||
width: fit-content; |
|||
|
|||
&:hover { |
|||
animation-play-state: paused; |
|||
} |
|||
|
|||
.logo-carousel-item { |
|||
flex-shrink: 0; |
|||
min-width: 200px; |
|||
padding: 0 2rem; |
|||
|
|||
@media (max-width: 768px) { |
|||
min-width: 150px; |
|||
padding: 0 1.5rem; |
|||
} |
|||
|
|||
@media (max-width: 576px) { |
|||
min-width: 120px; |
|||
padding: 0 1rem; |
|||
} |
|||
|
|||
.logo { |
|||
height: 3rem; |
|||
transition: |
|||
opacity 0.3s ease, |
|||
transform 0.3s ease; |
|||
width: 7.5rem; |
|||
|
|||
&:hover { |
|||
opacity: 0.8; |
|||
} |
|||
|
|||
&.mask { |
|||
background-color: rgba(var(--dark-secondary-text)); |
|||
mask-position: center; |
|||
mask-repeat: no-repeat; |
|||
mask-size: contain; |
|||
} |
|||
|
|||
&.logo-alternative-to { |
|||
mask-image: url('/assets/images/logo-alternative-to.svg'); |
|||
} |
|||
|
|||
&.logo-awesome { |
|||
background-image: url('/assets/images/logo-awesome.png'); |
|||
background-position: center; |
|||
background-repeat: no-repeat; |
|||
background-size: contain; |
|||
filter: grayscale(1); |
|||
} |
|||
|
|||
&.logo-dev-community { |
|||
mask-image: url('/assets/images/logo-dev-community.svg'); |
|||
} |
|||
|
|||
&.logo-hacker-news { |
|||
mask-image: url('/assets/images/logo-hacker-news.svg'); |
|||
} |
|||
|
|||
&.logo-openalternative { |
|||
mask-image: url('/assets/images/logo-openalternative.svg'); |
|||
} |
|||
|
|||
&.logo-privacy-tools { |
|||
mask-image: url('/assets/images/logo-privacy-tools.svg'); |
|||
} |
|||
|
|||
&.logo-product-hunt { |
|||
background-image: url('/assets/images/logo-product-hunt.png'); |
|||
background-position: center; |
|||
background-repeat: no-repeat; |
|||
background-size: contain; |
|||
filter: grayscale(1); |
|||
} |
|||
|
|||
&.logo-reddit { |
|||
mask-image: url('/assets/images/logo-reddit.svg'); |
|||
max-height: 1rem; |
|||
} |
|||
|
|||
&.logo-sackgeld { |
|||
mask-image: url('/assets/images/logo-sackgeld.png'); |
|||
} |
|||
|
|||
&.logo-selfh-st { |
|||
mask-image: url('/assets/images/logo-selfh-st.svg'); |
|||
max-height: 1.25rem; |
|||
} |
|||
|
|||
&.logo-sourceforge { |
|||
mask-image: url('/assets/images/logo-sourceforge.svg'); |
|||
} |
|||
|
|||
&.logo-umbrel { |
|||
mask-image: url('/assets/images/logo-umbrel.svg'); |
|||
max-height: 1.5rem; |
|||
} |
|||
|
|||
&.logo-unraid { |
|||
mask-image: url('/assets/images/logo-unraid.svg'); |
|||
} |
|||
|
|||
@media (max-width: 768px) { |
|||
height: 2.5rem; |
|||
width: 6rem; |
|||
} |
|||
|
|||
@media (max-width: 576px) { |
|||
height: 2rem; |
|||
width: 5rem; |
|||
} |
|||
} |
|||
} |
|||
|
|||
@keyframes scroll { |
|||
0% { |
|||
transform: translateX(0); |
|||
} |
|||
100% { |
|||
transform: translateX(-50%); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
:host-context(.theme-dark) { |
|||
.logo-carousel-container { |
|||
&::before { |
|||
background: linear-gradient( |
|||
to right, |
|||
var(--dark-background) 0%, |
|||
rgba(var(--palette-background-background-dark), 0) 100% |
|||
); |
|||
} |
|||
|
|||
&::after { |
|||
background: linear-gradient( |
|||
to left, |
|||
var(--dark-background) 0%, |
|||
rgba(var(--palette-background-background-dark), 0) 100% |
|||
); |
|||
} |
|||
|
|||
.logo { |
|||
&.logo-alternative-to, |
|||
&.logo-dev-community, |
|||
&.logo-hacker-news, |
|||
&.logo-openalternative, |
|||
&.logo-privacy-tools, |
|||
&.logo-reddit, |
|||
&.logo-sackgeld, |
|||
&.logo-selfh-st, |
|||
&.logo-sourceforge, |
|||
&.logo-umbrel, |
|||
&.logo-unraid { |
|||
background-color: rgba(var(--light-primary-text)); |
|||
} |
|||
} |
|||
} |
|||
} |
@ -0,0 +1,13 @@ |
|||
import type { Meta, StoryObj } from '@storybook/angular'; |
|||
|
|||
import { GfLogoCarouselComponent } from './logo-carousel.component'; |
|||
|
|||
const meta: Meta<GfLogoCarouselComponent> = { |
|||
title: 'Logo Carousel', |
|||
component: GfLogoCarouselComponent |
|||
}; |
|||
|
|||
export default meta; |
|||
type Story = StoryObj<GfLogoCarouselComponent>; |
|||
|
|||
export const Default: Story = {}; |
@ -0,0 +1,110 @@ |
|||
import { CommonModule } from '@angular/common'; |
|||
import { ChangeDetectionStrategy, Component } from '@angular/core'; |
|||
|
|||
import { LogoItem } from './interfaces/interfaces'; |
|||
|
|||
@Component({ |
|||
changeDetection: ChangeDetectionStrategy.OnPush, |
|||
imports: [CommonModule], |
|||
selector: 'gf-logo-carousel', |
|||
styleUrls: ['./logo-carousel.component.scss'], |
|||
templateUrl: './logo-carousel.component.html' |
|||
}) |
|||
export class GfLogoCarouselComponent { |
|||
public readonly logos: LogoItem[] = [ |
|||
{ |
|||
className: 'logo-alternative-to', |
|||
isMask: true, |
|||
name: 'AlternativeTo', |
|||
title: 'AlternativeTo - Crowdsourced software recommendations', |
|||
url: 'https://alternativeto.net' |
|||
}, |
|||
{ |
|||
className: 'logo-awesome', |
|||
name: 'Awesome Selfhosted', |
|||
title: |
|||
'Awesome-Selfhosted: A list of Free Software network services and web applications which can be hosted on your own servers', |
|||
url: 'https://github.com/awesome-selfhosted/awesome-selfhosted' |
|||
}, |
|||
{ |
|||
className: 'logo-dev-community', |
|||
isMask: true, |
|||
name: 'DEV Community', |
|||
title: |
|||
'DEV Community - A constructive and inclusive social network for software developers', |
|||
url: 'https://dev.to' |
|||
}, |
|||
{ |
|||
className: 'logo-hacker-news', |
|||
isMask: true, |
|||
name: 'Hacker News', |
|||
title: 'Hacker News', |
|||
url: 'https://news.ycombinator.com' |
|||
}, |
|||
{ |
|||
className: 'logo-openalternative', |
|||
isMask: true, |
|||
name: 'OpenAlternative', |
|||
title: 'OpenAlternative: Open Source Alternatives to Popular Software', |
|||
url: 'https://openalternative.co' |
|||
}, |
|||
{ |
|||
className: 'logo-privacy-tools', |
|||
isMask: true, |
|||
name: 'Privacy Tools', |
|||
title: 'Privacy Tools: Software Alternatives and Encryption', |
|||
url: 'https://www.privacytools.io' |
|||
}, |
|||
{ |
|||
className: 'logo-product-hunt', |
|||
name: 'Product Hunt', |
|||
title: 'Product Hunt – The best new products in tech.', |
|||
url: 'https://www.producthunt.com' |
|||
}, |
|||
{ |
|||
className: 'logo-reddit', |
|||
isMask: true, |
|||
name: 'Reddit', |
|||
title: 'Reddit - Dive into anything', |
|||
url: 'https://www.reddit.com' |
|||
}, |
|||
{ |
|||
className: 'logo-sackgeld', |
|||
isMask: true, |
|||
name: 'Sackgeld', |
|||
title: 'Sackgeld.com – Apps für ein höheres Sackgeld', |
|||
url: 'https://www.sackgeld.com' |
|||
}, |
|||
{ |
|||
className: 'logo-selfh-st', |
|||
isMask: true, |
|||
name: 'selfh.st', |
|||
title: 'selfh.st — Self-hosted content and software', |
|||
url: 'https://selfh.st' |
|||
}, |
|||
{ |
|||
className: 'logo-sourceforge', |
|||
isMask: true, |
|||
name: 'SourceForge', |
|||
title: |
|||
'SourceForge: The Complete Open-Source and Business Software Platform', |
|||
url: 'https://sourceforge.net' |
|||
}, |
|||
{ |
|||
className: 'logo-umbrel', |
|||
isMask: true, |
|||
name: 'Umbrel', |
|||
title: 'Umbrel — A personal server OS for self-hosting', |
|||
url: 'https://umbrel.com' |
|||
}, |
|||
{ |
|||
className: 'logo-unraid', |
|||
isMask: true, |
|||
name: 'Unraid', |
|||
title: 'Unraid | Unleash Your Hardware', |
|||
url: 'https://unraid.net' |
|||
} |
|||
]; |
|||
|
|||
public readonly logosRepeated = [...this.logos, ...this.logos]; |
|||
} |
Loading…
Reference in new issue