first pass - kryz inspired
This commit is contained in:
@@ -0,0 +1,65 @@
|
||||
<section class="about">
|
||||
<div class="container">
|
||||
<div class="about-intro">
|
||||
<img src="assets/svg/orange-flower.svg" alt="" class="about-flower-decor" aria-hidden="true">
|
||||
<h2>About <span class="text-accent">KMountain Flower</span></h2>
|
||||
<p class="section-intro">
|
||||
For nearly four decades, KMountain Flower has been the voice of our
|
||||
community — a nonprofit, listener-supported radio station dedicated to
|
||||
music, local news, and the stories that bind mountain towns together.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="about-grid">
|
||||
<div class="about-card">
|
||||
<div class="card-icon">🎵</div>
|
||||
<h3>Our Music</h3>
|
||||
<p>
|
||||
From bluegrass and folk to jazz and classical, our playlists reflect
|
||||
the rich cultural tapestry of the high country and its neighbors. We
|
||||
feature local artists alongside the world's best voices.
|
||||
</p>
|
||||
</div>
|
||||
<div class="about-card">
|
||||
<div class="card-icon">🤝</div>
|
||||
<h3>Our Community</h3>
|
||||
<p>
|
||||
Every show is staffed by volunteers who live and work in these
|
||||
mountains. From high school DJs to retired teachers, our team is your
|
||||
community — passionate about sharing what they love.
|
||||
</p>
|
||||
</div>
|
||||
<div class="about-card">
|
||||
<div class="card-icon">📡</div>
|
||||
<h3>Our Reach</h3>
|
||||
<p>
|
||||
Over the air on 98.7 FM and streaming live worldwide. Whether you're
|
||||
hiking the ridgeline or on the other side of the planet, our signal
|
||||
— and our welcome — goes everywhere.
|
||||
</p>
|
||||
</div>
|
||||
<div class="about-card">
|
||||
<div class="card-icon">🌱</div>
|
||||
<h3>Our Mission</h3>
|
||||
<p>
|
||||
To keep public radio free, independent, and deeply rooted in place.
|
||||
No corporate advertising, no spin — just music, conversation, and
|
||||
community served with care.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="about-cta">
|
||||
<div class="about-flower-divider" aria-hidden="true">
|
||||
<img src="assets/svg/small-flower.svg" alt="">
|
||||
</div>
|
||||
<h3>Become a Member</h3>
|
||||
<p class="section-intro">
|
||||
As a 501(c)(3) nonprofit, every donation keeps our airwaves free and our
|
||||
signal strong. Members receive exclusive perks and the satisfaction of
|
||||
knowing they helped make this possible.
|
||||
</p>
|
||||
<a routerLink="/donate" class="btn">Join the Station</a>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
@@ -0,0 +1,87 @@
|
||||
@use '../../styles/variables' as *;
|
||||
@use '../../styles/mixins' as *;
|
||||
|
||||
.about {
|
||||
padding: $spacing-3xl 0;
|
||||
background: var(--color-cream);
|
||||
}
|
||||
|
||||
.about-intro {
|
||||
text-align: center;
|
||||
margin-bottom: $spacing-2xl;
|
||||
|
||||
.about-flower-decor {
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
margin: 0 auto $spacing-md;
|
||||
opacity: 0.6;
|
||||
animation: float 5s ease-in-out infinite;
|
||||
}
|
||||
}
|
||||
|
||||
.about-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
|
||||
gap: $spacing-lg;
|
||||
margin-bottom: $spacing-3xl;
|
||||
}
|
||||
|
||||
.about-card {
|
||||
@include card-style;
|
||||
padding: $spacing-xl;
|
||||
text-align: center;
|
||||
background: var(--color-white);
|
||||
|
||||
.card-icon {
|
||||
font-size: 2.5rem;
|
||||
margin-bottom: $spacing-md;
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-size: 1.3rem;
|
||||
margin-bottom: $spacing-sm;
|
||||
color: var(--color-primary);
|
||||
}
|
||||
|
||||
p {
|
||||
font-size: 0.95rem;
|
||||
color: var(--color-dark);
|
||||
line-height: 1.7;
|
||||
}
|
||||
}
|
||||
|
||||
.about-cta {
|
||||
text-align: center;
|
||||
padding: $spacing-2xl $spacing-lg;
|
||||
background: $mixed-gradient;
|
||||
border-radius: $radius-xl;
|
||||
color: var(--color-white);
|
||||
|
||||
.about-flower-divider {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
margin: 0 auto $spacing-md;
|
||||
|
||||
img {
|
||||
width: 100%;
|
||||
filter: brightness(1.2);
|
||||
}
|
||||
}
|
||||
|
||||
h3 {
|
||||
color: var(--color-white);
|
||||
font-size: 1.8rem;
|
||||
margin-bottom: $spacing-sm;
|
||||
}
|
||||
|
||||
.section-intro {
|
||||
color: rgba(255, 255, 255, 0.85);
|
||||
margin-bottom: $spacing-lg;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: #{$bp-md - 1px}) {
|
||||
.about-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
import { Component } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'app-about',
|
||||
standalone: true,
|
||||
imports: [],
|
||||
templateUrl: './about.component.html',
|
||||
styleUrl: './about.component.scss',
|
||||
})
|
||||
export class AboutComponent {}
|
||||
@@ -0,0 +1,8 @@
|
||||
import { ApplicationConfig, provideBrowserGlobalErrorListeners } from '@angular/core';
|
||||
import { provideRouter } from '@angular/router';
|
||||
|
||||
import { routes } from './app.routes';
|
||||
|
||||
export const appConfig: ApplicationConfig = {
|
||||
providers: [provideBrowserGlobalErrorListeners(), provideRouter(routes)],
|
||||
};
|
||||
@@ -0,0 +1,5 @@
|
||||
<app-navbar></app-navbar>
|
||||
<main>
|
||||
<router-outlet></router-outlet>
|
||||
</main>
|
||||
<app-footer></app-footer>
|
||||
@@ -0,0 +1,36 @@
|
||||
import { Routes } from '@angular/router';
|
||||
|
||||
export const routes: Routes = [
|
||||
{ path: '', redirectTo: '/', pathMatch: 'full' },
|
||||
{
|
||||
path: '',
|
||||
loadComponent: () =>
|
||||
import('./hero/hero.component').then((m) => m.HeroComponent),
|
||||
},
|
||||
{
|
||||
path: 'about',
|
||||
loadComponent: () =>
|
||||
import('./about/about.component').then((m) => m.AboutComponent),
|
||||
},
|
||||
{
|
||||
path: 'schedule',
|
||||
loadComponent: () =>
|
||||
import('./schedule/schedule.component').then((m) => m.ScheduleComponent),
|
||||
},
|
||||
{
|
||||
path: 'donate',
|
||||
loadComponent: () =>
|
||||
import('./donate/donate.component').then((m) => m.DonateComponent),
|
||||
},
|
||||
{
|
||||
path: 'events',
|
||||
loadComponent: () =>
|
||||
import('./events/events.component').then((m) => m.EventsComponent),
|
||||
},
|
||||
{
|
||||
path: 'contact',
|
||||
loadComponent: () =>
|
||||
import('./contact/contact.component').then((m) => m.ContactComponent),
|
||||
},
|
||||
{ path: '**', redirectTo: '' },
|
||||
];
|
||||
@@ -0,0 +1,13 @@
|
||||
@use '../styles/variables' as *;
|
||||
|
||||
app-navbar {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
z-index: 200;
|
||||
}
|
||||
|
||||
main {
|
||||
padding-top: 70px;
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { RouterOutlet } from '@angular/router';
|
||||
import { NavbarComponent } from './navbar/navbar.component';
|
||||
import { FooterComponent } from './footer/footer.component';
|
||||
|
||||
@Component({
|
||||
selector: 'app-root',
|
||||
standalone: true,
|
||||
imports: [RouterOutlet, NavbarComponent, FooterComponent],
|
||||
templateUrl: './app.html',
|
||||
styleUrl: './app.scss',
|
||||
})
|
||||
export class App {}
|
||||
@@ -0,0 +1,65 @@
|
||||
<section class="contact">
|
||||
<div class="container">
|
||||
<div class="contact-header">
|
||||
<img src="assets/svg/small-flower.svg" alt="" class="contact-flower" aria-hidden="true">
|
||||
<h2>Get in <span class="text-accent">Touch</span></h2>
|
||||
<p class="section-intro">
|
||||
Have a song request, want to volunteer, or just want to say hello?
|
||||
We'd love to hear from you.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="contact-grid">
|
||||
<!-- Contact form -->
|
||||
<div class="contact-form-wrapper">
|
||||
<form class="contact-form" (ngSubmit)="onSubmit()" #contactForm="ngForm">
|
||||
<div class="form-group">
|
||||
<label for="name">Your Name</label>
|
||||
<input id="name" type="text" ngModel name="name" required placeholder="Jane Doe">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="email">Email Address</label>
|
||||
<input id="email" type="email" ngModel name="email" required placeholder="jane@example.com">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="subject">Subject</label>
|
||||
<select id="subject" ngModel name="subject" required>
|
||||
<option value="" disabled selected>Choose a topic</option>
|
||||
<option value="general">General Inquiry</option>
|
||||
<option value="volunteer">Volunteer</option>
|
||||
<option value="donation">Donation Question</option>
|
||||
<option value="advertising">Community Announcement</option>
|
||||
<option value="song">Song Request</option>
|
||||
<option value="technical">Technical Support</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="message">Message</label>
|
||||
<textarea id="message" rows="5" ngModel name="message" required placeholder="Your message..."></textarea>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-form">Send Message</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<!-- Station info -->
|
||||
<div class="contact-info">
|
||||
<div class="info-card">
|
||||
<h4><span aria-hidden="true">📍</span> Studio Location</h4>
|
||||
<p>42 Pine Street<br>Mountain View, CO 80424</p>
|
||||
</div>
|
||||
<div class="info-card">
|
||||
<h4><span aria-hidden="true">📞</span> Phone</h4>
|
||||
<p>(970) 555-0198<br>Mon–Fri 8 AM – 6 MT</p>
|
||||
</div>
|
||||
<div class="info-card">
|
||||
<h4><span aria-hidden="true">✉️</span> Email</h4>
|
||||
<p><a href="mailto:hello@kmountainflower.org">hello@kmountainflower.org</a></p>
|
||||
</div>
|
||||
<div class="info-card">
|
||||
<h4><span aria-hidden="true">📡</span> Frequencies</h4>
|
||||
<p>98.7 FM — Mountain Region<br>Stream: kmountainflower.org/live</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
@@ -0,0 +1,135 @@
|
||||
@use '../../styles/variables' as *;
|
||||
@use '../../styles/mixins' as *;
|
||||
|
||||
.contact {
|
||||
padding: $spacing-3xl 0;
|
||||
background: var(--color-cream);
|
||||
}
|
||||
|
||||
.contact-header {
|
||||
text-align: center;
|
||||
margin-bottom: $spacing-2xl;
|
||||
|
||||
.contact-flower {
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
margin: 0 auto $spacing-md;
|
||||
opacity: 0.5;
|
||||
}
|
||||
}
|
||||
|
||||
.contact-grid {
|
||||
display: grid;
|
||||
grid-template-columns: 1.5fr 1fr;
|
||||
gap: $spacing-2xl;
|
||||
align-items: start;
|
||||
}
|
||||
|
||||
// Form
|
||||
.contact-form-wrapper {
|
||||
background: var(--color-white);
|
||||
padding: $spacing-xl;
|
||||
border-radius: $radius-lg;
|
||||
box-shadow: $shadow-md;
|
||||
}
|
||||
|
||||
.contact-form {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: $spacing-md;
|
||||
}
|
||||
|
||||
.form-group {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: $spacing-xs;
|
||||
|
||||
label {
|
||||
font-weight: 600;
|
||||
font-size: 0.9rem;
|
||||
color: var(--color-primary);
|
||||
}
|
||||
|
||||
input,
|
||||
select,
|
||||
textarea {
|
||||
padding: $spacing-sm;
|
||||
border: 1px solid var(--color-light);
|
||||
border-radius: $radius-sm;
|
||||
font-family: var(--font-primary);
|
||||
font-size: 0.95rem;
|
||||
color: var(--color-dark);
|
||||
background: var(--color-white);
|
||||
transition: border-color $transition-fast, box-shadow $transition-fast;
|
||||
|
||||
&:focus {
|
||||
outline: none;
|
||||
border-color: var(--color-accent);
|
||||
box-shadow: 0 0 0 3px rgba(232, 122, 46, 0.15);
|
||||
}
|
||||
|
||||
&::placeholder {
|
||||
color: var(--color-medium);
|
||||
}
|
||||
}
|
||||
|
||||
textarea {
|
||||
resize: vertical;
|
||||
min-height: 120px;
|
||||
}
|
||||
}
|
||||
|
||||
.btn-form {
|
||||
@include button-style($accent-orange, $neutral-white, $accent-orange-dark);
|
||||
align-self: flex-start;
|
||||
font-size: 1rem;
|
||||
padding: $spacing-sm $spacing-xl;
|
||||
}
|
||||
|
||||
// Info
|
||||
.contact-info {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: $spacing-md;
|
||||
}
|
||||
|
||||
.info-card {
|
||||
background: var(--color-white);
|
||||
padding: $spacing-lg;
|
||||
border-radius: $radius-md;
|
||||
box-shadow: $shadow-sm;
|
||||
|
||||
h4 {
|
||||
font-size: 1rem;
|
||||
color: var(--color-primary);
|
||||
margin-bottom: $spacing-sm;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: $spacing-xs;
|
||||
|
||||
span {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
}
|
||||
|
||||
p {
|
||||
font-size: 0.9rem;
|
||||
color: var(--color-dark);
|
||||
line-height: 1.6;
|
||||
|
||||
a {
|
||||
color: var(--color-accent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: #{$bp-md - 1px}) {
|
||||
.contact-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.btn-form {
|
||||
width: 100%;
|
||||
justify-content: center;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
|
||||
@Component({
|
||||
selector: 'app-contact',
|
||||
standalone: true,
|
||||
imports: [FormsModule],
|
||||
templateUrl: './contact.component.html',
|
||||
styleUrl: './contact.component.scss',
|
||||
})
|
||||
export class ContactComponent {
|
||||
onSubmit(): void {
|
||||
alert('Thank you for your message! We will get back to you shortly.');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
<section class="donate">
|
||||
<!-- Hero banner -->
|
||||
<div class="donate-banner">
|
||||
<div class="donate-banner-overlay">
|
||||
<div class="container donate-banner-content">
|
||||
<img src="assets/svg/orange-flower.svg" alt="" class="donate-flower-hero" aria-hidden="true">
|
||||
<h2>Keep the Music <span class="text-accent">Free</span></h2>
|
||||
<p class="donate-subtitle">
|
||||
KMountain Flower Radio is 100% listener-funded and independent.
|
||||
Your gift keeps our signal strong and our airwaves free for everyone.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="container">
|
||||
<!-- Donation tiers -->
|
||||
<div class="donate-tiers">
|
||||
<h3>Choose Your Level of Support</h3>
|
||||
<div class="tiers-grid">
|
||||
<div class="tier-card" *ngFor="let tier of tiers">
|
||||
<div class="tier-icon">{{ tier.icon }}</div>
|
||||
<div class="tier-amount">${{ tier.amount }}</div>
|
||||
<div class="tier-period">per month</div>
|
||||
<h4>{{ tier.name }}</h4>
|
||||
<ul class="tier-benefits">
|
||||
<li *ngFor="let benefit of tier.benefits">{{ benefit }}</li>
|
||||
</ul>
|
||||
<a href="#" class="btn btn-tier">Select {{ tier.name }}</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- One-time donation -->
|
||||
<div class="donate-one-time">
|
||||
<div class="donate-flower-divider" aria-hidden="true">
|
||||
<img src="assets/svg/small-flower.svg" alt="">
|
||||
</div>
|
||||
<h3>Or Make a One-Time Gift</h3>
|
||||
<p class="section-intro">
|
||||
Every dollar matters — from $5 to $5,000. No amount is too small to make
|
||||
a difference. All donations are tax-deductible (EIN: 84-XXXXXXX).
|
||||
</p>
|
||||
<a href="#" class="btn btn-lg">Give Any Amount</a>
|
||||
</div>
|
||||
|
||||
<!-- Why donate -->
|
||||
<div class="donate-why">
|
||||
<div class="why-grid">
|
||||
<div class="why-item">
|
||||
<span class="why-icon">📻</span>
|
||||
<strong>98.7 FM Signal</strong>
|
||||
<p>Covering 3 mountain counties and the valleys between</p>
|
||||
</div>
|
||||
<div class="why-item">
|
||||
<span class="why-icon">🎙️</span>
|
||||
<strong>24/7 On-Air</strong>
|
||||
<p>Over 15,000 hours of programming per year</p>
|
||||
</div>
|
||||
<div class="why-item">
|
||||
<span class="why-icon">🌍</span>
|
||||
<strong>Worldwide Stream</strong>
|
||||
<p>Accessible from every corner of the globe, free forever</p>
|
||||
</div>
|
||||
<div class="why-item">
|
||||
<span class="why-icon">🎓</span>
|
||||
<strong>Youth Programs</strong>
|
||||
<p>Free radio training for 200+ local students each year</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
@@ -0,0 +1,197 @@
|
||||
@use '../../styles/variables' as *;
|
||||
@use '../../styles/mixins' as *;
|
||||
|
||||
.donate {
|
||||
background: var(--color-cream);
|
||||
}
|
||||
|
||||
// Banner
|
||||
.donate-banner {
|
||||
position: relative;
|
||||
margin-bottom: $spacing-3xl;
|
||||
}
|
||||
|
||||
.donate-banner-overlay {
|
||||
background: $mixed-gradient;
|
||||
padding: $spacing-3xl $spacing-lg;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.donate-banner-content {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.donate-flower-hero {
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
margin: 0 auto $spacing-md;
|
||||
opacity: 0.7;
|
||||
animation: float 4s ease-in-out infinite;
|
||||
}
|
||||
|
||||
.donate-banner h2 {
|
||||
color: var(--color-white);
|
||||
font-size: 2.4rem;
|
||||
margin-bottom: $spacing-md;
|
||||
}
|
||||
|
||||
.donate-subtitle {
|
||||
color: rgba(255, 255, 255, 0.85);
|
||||
font-size: 1.1rem;
|
||||
max-width: 550px;
|
||||
margin: 0 auto;
|
||||
line-height: 1.7;
|
||||
}
|
||||
|
||||
// Tiers
|
||||
.donate-tiers {
|
||||
text-align: center;
|
||||
margin-bottom: $spacing-3xl;
|
||||
|
||||
h3 {
|
||||
font-size: 1.8rem;
|
||||
margin-bottom: $spacing-xl;
|
||||
}
|
||||
}
|
||||
|
||||
.tiers-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
|
||||
gap: $spacing-lg;
|
||||
margin-bottom: $spacing-xl;
|
||||
}
|
||||
|
||||
.tier-card {
|
||||
@include card-style;
|
||||
padding: $spacing-xl;
|
||||
text-align: center;
|
||||
background: var(--color-white);
|
||||
border-top: 4px solid var(--color-accent);
|
||||
|
||||
.tier-icon {
|
||||
font-size: 2rem;
|
||||
margin-bottom: $spacing-sm;
|
||||
}
|
||||
|
||||
.tier-amount {
|
||||
font-size: 2.8rem;
|
||||
font-weight: 700;
|
||||
color: var(--color-accent);
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.tier-period {
|
||||
font-size: 0.85rem;
|
||||
color: var(--color-medium);
|
||||
margin-bottom: $spacing-md;
|
||||
}
|
||||
|
||||
h4 {
|
||||
font-size: 1.2rem;
|
||||
color: var(--color-primary);
|
||||
margin-bottom: $spacing-md;
|
||||
}
|
||||
|
||||
.tier-benefits {
|
||||
list-style: none;
|
||||
text-align: left;
|
||||
margin-bottom: $spacing-lg;
|
||||
|
||||
li {
|
||||
padding: $spacing-xs 0;
|
||||
font-size: 0.9rem;
|
||||
color: var(--color-dark);
|
||||
border-bottom: 1px solid var(--color-light);
|
||||
|
||||
&::before {
|
||||
content: '✓ ';
|
||||
color: $success-green;
|
||||
font-weight: 700;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.btn-tier {
|
||||
@include button-style($accent-orange, $neutral-white, $accent-orange-dark);
|
||||
display: inline-block;
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
|
||||
// One-time
|
||||
.donate-one-time {
|
||||
text-align: center;
|
||||
padding: $spacing-2xl $spacing-lg;
|
||||
background: var(--color-primary);
|
||||
border-radius: $radius-xl;
|
||||
margin-bottom: $spacing-3xl;
|
||||
|
||||
.donate-flower-divider {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
margin: 0 auto $spacing-md;
|
||||
|
||||
img {
|
||||
width: 100%;
|
||||
filter: brightness(1.2);
|
||||
}
|
||||
}
|
||||
|
||||
h3 {
|
||||
color: var(--color-white);
|
||||
font-size: 1.6rem;
|
||||
margin-bottom: $spacing-sm;
|
||||
}
|
||||
|
||||
.section-intro {
|
||||
color: rgba(255, 255, 255, 0.8);
|
||||
margin-bottom: $spacing-lg;
|
||||
}
|
||||
|
||||
.btn-lg {
|
||||
@include button-style($accent-orange, $neutral-white, $accent-orange-dark);
|
||||
font-size: 1.2rem;
|
||||
padding: $spacing-md $spacing-2xl;
|
||||
}
|
||||
}
|
||||
|
||||
// Why
|
||||
.donate-why {
|
||||
padding-bottom: $spacing-xl;
|
||||
}
|
||||
|
||||
.why-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
|
||||
gap: $spacing-lg;
|
||||
|
||||
.why-item {
|
||||
text-align: center;
|
||||
padding: $spacing-lg;
|
||||
|
||||
.why-icon {
|
||||
display: block;
|
||||
font-size: 2.5rem;
|
||||
margin-bottom: $spacing-sm;
|
||||
}
|
||||
|
||||
strong {
|
||||
display: block;
|
||||
color: var(--color-primary);
|
||||
margin-bottom: $spacing-xs;
|
||||
font-size: 1.05rem;
|
||||
}
|
||||
|
||||
p {
|
||||
font-size: 0.9rem;
|
||||
color: var(--color-medium);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: #{$bp-md - 1px}) {
|
||||
.donate-banner h2 { font-size: 1.8rem; }
|
||||
.tiers-grid { grid-template-columns: 1fr; max-width: 320px; margin-left: auto; margin-right: auto; }
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { NgFor } from '@angular/common';
|
||||
|
||||
interface Tier {
|
||||
name: string;
|
||||
amount: number;
|
||||
icon: string;
|
||||
benefits: string[];
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'app-donate',
|
||||
standalone: true,
|
||||
imports: [NgFor],
|
||||
templateUrl: './donate.component.html',
|
||||
styleUrl: './donate.component.scss',
|
||||
})
|
||||
export class DonateComponent {
|
||||
readonly tiers: Tier[] = [
|
||||
{
|
||||
name: 'Seed',
|
||||
amount: 5,
|
||||
icon: '🌱',
|
||||
benefits: [
|
||||
'Digital thank-you card',
|
||||
'Name listed on our website',
|
||||
'Quarterly newsletter',
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'Stream',
|
||||
amount: 15,
|
||||
icon: '🎵',
|
||||
benefits: [
|
||||
'All Seed benefits',
|
||||
'KMountain Flower pin',
|
||||
'Priority show-request line',
|
||||
'Annual station update call',
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'Ridge',
|
||||
amount: 30,
|
||||
icon: '🏔️',
|
||||
benefits: [
|
||||
'All Stream benefits',
|
||||
'Official member patch',
|
||||
'Exclusive show invitations',
|
||||
'Annual station tour',
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'Summit',
|
||||
amount: 60,
|
||||
icon: '⭐',
|
||||
benefits: [
|
||||
'All Ridge benefits',
|
||||
'Featured on the Summit Wall',
|
||||
'Name on-air during anniversary special',
|
||||
'Lifetime patron recognition',
|
||||
],
|
||||
},
|
||||
];
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
<section class="events">
|
||||
<div class="container">
|
||||
<div class="events-header">
|
||||
<img src="assets/svg/small-flower.svg" alt="" class="events-flower" aria-hidden="true">
|
||||
<h2>Upcoming <span class="text-accent">Events</span></h2>
|
||||
<p class="section-intro">
|
||||
Come meet the team, enjoy live music, and support public radio in
|
||||
person. All events are open to the community — friends and family of
|
||||
listeners welcome.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="events-list">
|
||||
<div class="event-card" *ngFor="let event of upcomingEvents">
|
||||
<div class="event-date">
|
||||
<span class="event-month">Jul</span>
|
||||
<span class="event-day">12</span>
|
||||
<span class="event-year">2026</span>
|
||||
</div>
|
||||
<div class="event-content">
|
||||
<h3>{{ event.title }}</h3>
|
||||
<p>{{ event.description }}</p>
|
||||
<div class="event-meta">
|
||||
<span class="event-location">
|
||||
<span aria-hidden="true">📍</span> {{ event.location }}
|
||||
</span>
|
||||
<a href="#" class="event-rsvp">Learn More →</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="event-icon" aria-hidden="true">{{ event.icon }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
@@ -0,0 +1,135 @@
|
||||
@use '../../styles/variables' as *;
|
||||
@use '../../styles/mixins' as *;
|
||||
|
||||
.events {
|
||||
padding: $spacing-3xl 0;
|
||||
background: var(--color-white);
|
||||
}
|
||||
|
||||
.events-header {
|
||||
text-align: center;
|
||||
margin-bottom: $spacing-2xl;
|
||||
|
||||
.events-flower {
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
margin: 0 auto $spacing-md;
|
||||
opacity: 0.5;
|
||||
}
|
||||
}
|
||||
|
||||
.events-list {
|
||||
max-width: 800px;
|
||||
margin: 0 auto;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: $spacing-lg;
|
||||
}
|
||||
|
||||
.event-card {
|
||||
@include card-style;
|
||||
display: flex;
|
||||
background: var(--color-white);
|
||||
overflow: hidden;
|
||||
|
||||
.event-date {
|
||||
flex-shrink: 0;
|
||||
background: $mixed-gradient;
|
||||
color: var(--color-white);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: $spacing-md $spacing-lg;
|
||||
min-width: 90px;
|
||||
text-align: center;
|
||||
|
||||
.event-month {
|
||||
font-size: 0.85rem;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.1em;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.event-day {
|
||||
font-size: 2.2rem;
|
||||
font-weight: 700;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.event-year {
|
||||
font-size: 0.75rem;
|
||||
opacity: 0.8;
|
||||
}
|
||||
}
|
||||
|
||||
.event-content {
|
||||
flex: 1;
|
||||
padding: $spacing-lg;
|
||||
|
||||
h3 {
|
||||
font-size: 1.3rem;
|
||||
color: var(--color-primary);
|
||||
margin-bottom: $spacing-sm;
|
||||
}
|
||||
|
||||
p {
|
||||
font-size: 0.95rem;
|
||||
color: var(--color-dark);
|
||||
line-height: 1.6;
|
||||
margin-bottom: $spacing-sm;
|
||||
}
|
||||
}
|
||||
|
||||
.event-meta {
|
||||
display: flex;
|
||||
gap: $spacing-md;
|
||||
align-items: center;
|
||||
flex-wrap: wrap;
|
||||
font-size: 0.85rem;
|
||||
color: var(--color-medium);
|
||||
|
||||
.event-location {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.event-rsvp {
|
||||
color: var(--color-accent);
|
||||
font-weight: 600;
|
||||
transition: color $transition-fast;
|
||||
|
||||
&:hover {
|
||||
color: var(--color-accent-dark);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.event-icon {
|
||||
flex-shrink: 0;
|
||||
font-size: 3rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding-right: $spacing-md;
|
||||
opacity: 0.7;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: #{$bp-md - 1px}) {
|
||||
.event-card {
|
||||
flex-direction: column;
|
||||
|
||||
.event-date {
|
||||
flex-direction: row;
|
||||
gap: $spacing-sm;
|
||||
padding: $spacing-sm $spacing-md;
|
||||
}
|
||||
|
||||
.event-icon {
|
||||
padding-right: 0;
|
||||
padding-top: $spacing-sm;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { NgFor } from '@angular/common';
|
||||
|
||||
interface Event {
|
||||
date: string;
|
||||
title: string;
|
||||
description: string;
|
||||
location: string;
|
||||
icon: string;
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'app-events',
|
||||
standalone: true,
|
||||
imports: [NgFor],
|
||||
templateUrl: './events.component.html',
|
||||
styleUrl: './events.component.scss',
|
||||
})
|
||||
export class EventsComponent {
|
||||
readonly upcomingEvents: Event[] = [
|
||||
{
|
||||
date: 'July 12, 2026',
|
||||
title: 'Summer Sounds Festival',
|
||||
description: 'A full day of live local music, community booths, and station meet-and-greet at the foothills park. Free admission — donations welcome.',
|
||||
location: 'Foothills Community Park',
|
||||
icon: '🎵',
|
||||
},
|
||||
{
|
||||
date: 'August 5, 2026',
|
||||
title: 'Annual Fundraiser Gala',
|
||||
description: 'Our biggest fundraiser of the year! Enjoy dinner, silent auction, and performances from past guest artists.',
|
||||
location: 'Mountain View Ballroom',
|
||||
icon: '🎙️',
|
||||
},
|
||||
{
|
||||
date: 'September 18, 2026',
|
||||
title: 'Volunteer Open House',
|
||||
description: 'Tour the studio, meet the team, and learn how you can help keep our free stream alive. New volunteers always welcome!',
|
||||
location: 'KMTN Studio — 42 Pine St',
|
||||
icon: '🤝',
|
||||
},
|
||||
{
|
||||
date: 'October 30, 2026',
|
||||
title: 'Harvest Moon Broadcast',
|
||||
description: 'Special live broadcast from the harvest moon gathering. Featuring folk, bluegrass, and indigenous music.',
|
||||
location: 'Ridgefield Amphitheater',
|
||||
icon: '🌙',
|
||||
},
|
||||
];
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
<footer class="footer">
|
||||
<div class="container">
|
||||
<div class="footer-top">
|
||||
<div class="footer-brand">
|
||||
<img src="assets/svg/small-flower.svg" alt="" class="footer-flower" aria-hidden="true">
|
||||
<h3>
|
||||
<span class="brand-m">K</span>MOUNTAIN
|
||||
<span class="brand-a">FLOWER</span> Radio
|
||||
</h3>
|
||||
<p class="footer-tagline">
|
||||
Community-powered nonprofit public radio — free to stream, funded by you.
|
||||
</p>
|
||||
<p class="footer-legal">
|
||||
KMountain Flower Radio is a 501(c)(3) nonprofit organization.<br>
|
||||
EIN: 84-XXXXXXX. All donations are tax-deductible.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="footer-links">
|
||||
<div class="footer-col">
|
||||
<h4>Quick Links</h4>
|
||||
<ul>
|
||||
<li><a routerLink="/about">About Us</a></li>
|
||||
<li><a routerLink="/schedule">Schedule</a></li>
|
||||
<li><a routerLink="/events">Events</a></li>
|
||||
<li><a routerLink="/donate">Donate</a></li>
|
||||
<li><a routerLink="/contact">Contact</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="footer-col">
|
||||
<h4>Support</h4>
|
||||
<ul>
|
||||
<li><a routerLink="/donate">Become a Member</a></li>
|
||||
<li><a href="#">Volunteer</a></li>
|
||||
<li><a href="#">Corporate Giving</a></li>
|
||||
<li><a href="#">Planned Giving</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="footer-col">
|
||||
<h4>Follow Us</h4>
|
||||
<div class="social-links">
|
||||
<a href="#" aria-label="Facebook" class="social-link">📘</a>
|
||||
<a href="#" aria-label="Twitter" class="social-link">🐦</a>
|
||||
<a href="#" aria-label="Instagram" class="social-link">📷</a>
|
||||
<a href="#" aria-label="YouTube" class="social-link">📺</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="footer-bottom">
|
||||
<p>© 1987–2026 KMountain Flower Radio. All rights reserved.</p>
|
||||
<p class="footer-made">
|
||||
Made with 🧡 in the mountains
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
@@ -0,0 +1,132 @@
|
||||
@use '../../styles/variables' as *;
|
||||
@use '../../styles/mixins' as *;
|
||||
|
||||
.footer {
|
||||
background: var(--color-primary-dark);
|
||||
color: rgba(255, 255, 255, 0.8);
|
||||
padding: $spacing-3xl 0 $spacing-lg;
|
||||
}
|
||||
|
||||
.footer-top {
|
||||
display: grid;
|
||||
grid-template-columns: 1.2fr 2fr;
|
||||
gap: $spacing-2xl;
|
||||
padding-bottom: $spacing-2xl;
|
||||
border-bottom: 1px solid rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
|
||||
.footer-brand {
|
||||
.footer-flower {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
margin-bottom: $spacing-sm;
|
||||
filter: brightness(1.1);
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-size: 1.4rem;
|
||||
color: var(--color-white);
|
||||
margin-bottom: $spacing-sm;
|
||||
line-height: 1.2;
|
||||
|
||||
.brand-m {
|
||||
color: var(--color-white);
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.brand-a {
|
||||
@include gradient-text(var(--color-accent-light), var(--color-accent));
|
||||
}
|
||||
}
|
||||
|
||||
.footer-tagline {
|
||||
font-size: 0.95rem;
|
||||
line-height: 1.6;
|
||||
margin-bottom: $spacing-md;
|
||||
}
|
||||
|
||||
.footer-legal {
|
||||
font-size: 0.8rem;
|
||||
color: rgba(255, 255, 255, 0.5);
|
||||
line-height: 1.5;
|
||||
}
|
||||
}
|
||||
|
||||
.footer-links {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
gap: $spacing-xl;
|
||||
align-self: start;
|
||||
}
|
||||
|
||||
.footer-col {
|
||||
h4 {
|
||||
color: var(--color-accent-light);
|
||||
font-size: 1rem;
|
||||
margin-bottom: $spacing-md;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
ul {
|
||||
list-style: none;
|
||||
|
||||
li {
|
||||
margin-bottom: $spacing-xs;
|
||||
|
||||
a {
|
||||
color: rgba(255, 255, 255, 0.7);
|
||||
font-size: 0.9rem;
|
||||
transition: color $transition-fast;
|
||||
|
||||
&:hover {
|
||||
color: var(--color-accent-light);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.social-links {
|
||||
display: flex;
|
||||
gap: $spacing-sm;
|
||||
|
||||
.social-link {
|
||||
font-size: 1.5rem;
|
||||
text-decoration: none;
|
||||
transition: transform $transition-fast;
|
||||
|
||||
&:hover {
|
||||
transform: scale(1.15);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.footer-bottom {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding-top: $spacing-lg;
|
||||
font-size: 0.85rem;
|
||||
color: rgba(255, 255, 255, 0.5);
|
||||
|
||||
.footer-made {
|
||||
font-style: italic;
|
||||
color: rgba(255, 255, 255, 0.4);
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: #{$bp-md - 1px}) {
|
||||
.footer-top {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.footer-links {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.footer-bottom {
|
||||
flex-direction: column;
|
||||
gap: $spacing-sm;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
import { Component } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'app-footer',
|
||||
standalone: true,
|
||||
imports: [],
|
||||
templateUrl: './footer.component.html',
|
||||
styleUrl: './footer.component.scss',
|
||||
})
|
||||
export class FooterComponent {}
|
||||
@@ -0,0 +1,42 @@
|
||||
<section class="hero">
|
||||
<!-- Mountain background layer -->
|
||||
<div class="hero-mountains" aria-hidden="true">
|
||||
<img src="assets/svg/mountain-silhouette.svg" alt="">
|
||||
</div>
|
||||
|
||||
<!-- Gradient overlay -->
|
||||
<div class="hero-gradient"></div>
|
||||
|
||||
<!-- Content -->
|
||||
<div class="hero-content container">
|
||||
<div class="hero-inner">
|
||||
<div class="hero-icon">
|
||||
<img src="assets/svg/orange-flower.svg" alt="" class="hero-flower">
|
||||
</div>
|
||||
<h1 class="hero-title">
|
||||
<span class="hero-line1">KMountain</span>
|
||||
<span class="hero-line2 text-accent">Flower Radio</span>
|
||||
</h1>
|
||||
<p class="hero-subtitle">
|
||||
Your community-powered, nonprofit radio station — bringing music,
|
||||
stories, and connection to the mountain towns and beyond since 1987.
|
||||
</p>
|
||||
<p class="hero-subtitle hero-tagline">
|
||||
Free to stream. Funded by you. Always on-air.
|
||||
</p>
|
||||
<div class="hero-actions">
|
||||
<a routerLink="/donate" class="btn btn-hero-primary">Support the Station</a>
|
||||
<a routerLink="/schedule" class="btn btn-hero-secondary">View Schedule</a>
|
||||
</div>
|
||||
<div class="hero-listeners">
|
||||
<span class="listeners-dot"></span>
|
||||
<span class="listeners-text">Live on-air now — Stream free worldwide</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Mountain divider at bottom -->
|
||||
<div class="hero-divider" aria-hidden="true">
|
||||
<img src="assets/svg/mountain-divider.svg" alt="">
|
||||
</div>
|
||||
</section>
|
||||
@@ -0,0 +1,166 @@
|
||||
@use '../../styles/variables' as *;
|
||||
@use '../../styles/mixins' as *;
|
||||
|
||||
.hero {
|
||||
position: relative;
|
||||
min-height: 100vh;
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.hero-mountains {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
z-index: 0;
|
||||
|
||||
img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
object-position: center bottom;
|
||||
}
|
||||
}
|
||||
|
||||
.hero-gradient {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
z-index: 1;
|
||||
background: $sky-gradient;
|
||||
opacity: 0.85;
|
||||
}
|
||||
|
||||
.hero-content {
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
text-align: center;
|
||||
padding: $spacing-3xl $spacing-lg;
|
||||
}
|
||||
|
||||
.hero-inner {
|
||||
@include fade-in;
|
||||
}
|
||||
|
||||
.hero-icon {
|
||||
margin-bottom: $spacing-lg;
|
||||
animation: float 4s ease-in-out infinite;
|
||||
|
||||
.hero-flower {
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
margin: 0 auto;
|
||||
filter: drop-shadow(0 4px 12px rgba(232, 122, 46, 0.4));
|
||||
}
|
||||
}
|
||||
|
||||
.hero-title {
|
||||
margin-bottom: $spacing-md;
|
||||
}
|
||||
|
||||
.hero-line1 {
|
||||
display: block;
|
||||
font-size: 3.5rem;
|
||||
font-weight: 700;
|
||||
color: var(--color-white);
|
||||
letter-spacing: 0.05em;
|
||||
}
|
||||
|
||||
.hero-line2 {
|
||||
display: block;
|
||||
font-size: 3rem;
|
||||
font-weight: 700;
|
||||
@include gradient-text(var(--color-accent-light), var(--color-accent));
|
||||
}
|
||||
|
||||
.hero-subtitle {
|
||||
font-size: 1.15rem;
|
||||
color: rgba(255, 255, 255, 0.85);
|
||||
max-width: 600px;
|
||||
margin: 0 auto $spacing-sm;
|
||||
line-height: 1.7;
|
||||
}
|
||||
|
||||
.hero-tagline {
|
||||
font-style: italic;
|
||||
color: var(--color-accent-muted);
|
||||
font-size: 1.05rem;
|
||||
}
|
||||
|
||||
.hero-actions {
|
||||
display: flex;
|
||||
gap: $spacing-md;
|
||||
justify-content: center;
|
||||
flex-wrap: wrap;
|
||||
margin: $spacing-lg 0;
|
||||
}
|
||||
|
||||
.btn-hero-primary {
|
||||
@include button-style($accent-orange, $neutral-white, $accent-orange-dark);
|
||||
font-size: 1.1rem;
|
||||
padding: $spacing-sm $spacing-xl;
|
||||
letter-spacing: 0.03em;
|
||||
}
|
||||
|
||||
.btn-hero-secondary {
|
||||
@include button-style(transparent, var(--color-white), rgba(255,255,255,0.15));
|
||||
border: 2px solid rgba(255, 255, 255, 0.4);
|
||||
font-size: 1.1rem;
|
||||
padding: $spacing-sm $spacing-xl;
|
||||
letter-spacing: 0.03em;
|
||||
|
||||
&:hover {
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
border-color: rgba(255, 255, 255, 0.7);
|
||||
}
|
||||
}
|
||||
|
||||
.hero-listeners {
|
||||
margin-top: $spacing-xl;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: $spacing-sm;
|
||||
font-size: 0.95rem;
|
||||
color: rgba(255, 255, 255, 0.7);
|
||||
}
|
||||
|
||||
.listeners-dot {
|
||||
display: inline-block;
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
border-radius: $radius-full;
|
||||
background: $success-green;
|
||||
animation: pulse 2s ease-in-out infinite;
|
||||
}
|
||||
|
||||
@keyframes pulse {
|
||||
0%, 100% { opacity: 1; box-shadow: 0 0 0 0 rgba(74, 158, 79, 0.4); }
|
||||
50% { opacity: 0.7; box-shadow: 0 0 0 6px rgba(74, 158, 79, 0); }
|
||||
}
|
||||
|
||||
.hero-divider {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
z-index: 3;
|
||||
|
||||
img {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
// Responsive
|
||||
@media (max-width: #{$bp-md - 1px}) {
|
||||
.hero-line1 { font-size: 2.5rem; }
|
||||
.hero-line2 { font-size: 2.2rem; }
|
||||
.hero-subtitle { font-size: 1rem; }
|
||||
.hero-flower { width: 70px; height: 70px; }
|
||||
.hero-actions { flex-direction: column; align-items: center; }
|
||||
}
|
||||
|
||||
@media (max-width: #{$bp-sm - 1px}) {
|
||||
.hero-line1 { font-size: 2rem; }
|
||||
.hero-line2 { font-size: 1.8rem; }
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
import { Component } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'app-hero',
|
||||
standalone: true,
|
||||
imports: [],
|
||||
templateUrl: './hero.component.html',
|
||||
styleUrl: './hero.component.scss',
|
||||
})
|
||||
export class HeroComponent {}
|
||||
@@ -0,0 +1,28 @@
|
||||
<nav class="navbar" role="navigation" aria-label="Main navigation">
|
||||
<div class="container navbar-inner">
|
||||
<a routerLink="/" class="navbar-brand" routerLinkActive="active">
|
||||
<img src="assets/svg/small-flower.svg" alt="" class="brand-flower" aria-hidden="true">
|
||||
<span class="brand-name">
|
||||
<span class="brand-mountain">K</span>MOUNTAIN
|
||||
<span class="brand-accent">FLOWER</span>
|
||||
</span>
|
||||
<span class="brand-tagline">Community Radio — Est. 1987</span>
|
||||
</a>
|
||||
|
||||
<button class="navbar-toggle" aria-label="Toggle menu" (click)="toggleMenu()">
|
||||
<span class="bar"></span>
|
||||
<span class="bar"></span>
|
||||
<span class="bar"></span>
|
||||
</button>
|
||||
|
||||
<div class="navbar-menu" [class.open]="menuOpen">
|
||||
<ul class="nav-links">
|
||||
<li><a routerLink="/about" routerLinkActive="active" (click)="closeMenu()">About</a></li>
|
||||
<li><a routerLink="/schedule" routerLinkActive="active" (click)="closeMenu()">Schedule</a></li>
|
||||
<li><a routerLink="/events" routerLinkActive="active" (click)="closeMenu()">Events</a></li>
|
||||
<li><a routerLink="/contact" routerLinkActive="active" (click)="closeMenu()">Contact</a></li>
|
||||
</ul>
|
||||
<a routerLink="/donate" class="btn btn-donate-nav" (click)="closeMenu()">Donate Now</a>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
@@ -0,0 +1,143 @@
|
||||
@use '../../styles/variables' as *;
|
||||
@use '../../styles/mixins' as *;
|
||||
|
||||
.navbar {
|
||||
background: var(--color-primary-dark);
|
||||
padding: $spacing-sm 0;
|
||||
position: sticky;
|
||||
top: 0;
|
||||
z-index: $z-sticky;
|
||||
box-shadow: $shadow-md;
|
||||
}
|
||||
|
||||
.navbar-inner {
|
||||
@include flex-between;
|
||||
}
|
||||
|
||||
.navbar-brand {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: $spacing-sm;
|
||||
text-decoration: none;
|
||||
color: var(--color-white);
|
||||
}
|
||||
|
||||
.brand-flower {
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
}
|
||||
|
||||
.brand-name {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
line-height: 1.1;
|
||||
}
|
||||
|
||||
.brand-mountain {
|
||||
font-family: var(--font-heading);
|
||||
font-size: 1.4rem;
|
||||
font-weight: 700;
|
||||
color: var(--color-white);
|
||||
letter-spacing: 0.08em;
|
||||
}
|
||||
|
||||
.brand-accent {
|
||||
font-family: var(--font-heading);
|
||||
font-size: 1.1rem;
|
||||
font-weight: 700;
|
||||
@include gradient-text(var(--color-accent-light), var(--color-accent));
|
||||
}
|
||||
|
||||
.brand-tagline {
|
||||
font-size: 0.65rem;
|
||||
color: var(--color-medium);
|
||||
letter-spacing: 0.1em;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.navbar-toggle {
|
||||
display: none;
|
||||
flex-direction: column;
|
||||
gap: 4px;
|
||||
background: none;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
padding: $spacing-xs;
|
||||
|
||||
.bar {
|
||||
display: block;
|
||||
width: 24px;
|
||||
height: 2px;
|
||||
background: var(--color-white);
|
||||
border-radius: 1px;
|
||||
transition: $transition-normal;
|
||||
}
|
||||
}
|
||||
|
||||
.navbar-menu {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: $spacing-lg;
|
||||
}
|
||||
|
||||
.nav-links {
|
||||
display: flex;
|
||||
list-style: none;
|
||||
gap: $spacing-md;
|
||||
|
||||
a {
|
||||
color: var(--color-light);
|
||||
font-size: 0.95rem;
|
||||
font-weight: 500;
|
||||
padding: $spacing-xs $spacing-sm;
|
||||
border-radius: $radius-sm;
|
||||
transition: color $transition-fast, background $transition-fast;
|
||||
|
||||
&:hover,
|
||||
&.active {
|
||||
color: var(--color-accent-light);
|
||||
background: rgba(232, 122, 46, 0.1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.btn-donate-nav {
|
||||
@include button-style($accent-orange, $neutral-white, $accent-orange-dark);
|
||||
padding: $spacing-xs $spacing-md;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
// Responsive
|
||||
@media (max-width: #{$bp-md - 1px}) {
|
||||
.navbar-toggle {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.navbar-menu {
|
||||
position: absolute;
|
||||
top: 100%;
|
||||
left: 0;
|
||||
right: 0;
|
||||
background: var(--color-primary-dark);
|
||||
flex-direction: column;
|
||||
padding: $spacing-md;
|
||||
gap: $spacing-md;
|
||||
box-shadow: $shadow-lg;
|
||||
transform: translateY(-10px);
|
||||
opacity: 0;
|
||||
pointer-events: none;
|
||||
transition: transform $transition-normal, opacity $transition-normal;
|
||||
|
||||
&.open {
|
||||
transform: translateY(0);
|
||||
opacity: 1;
|
||||
pointer-events: auto;
|
||||
}
|
||||
}
|
||||
|
||||
.nav-links {
|
||||
flex-direction: column;
|
||||
width: 100%;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { RouterLink, RouterLinkActive } from '@angular/router';
|
||||
|
||||
@Component({
|
||||
selector: 'app-navbar',
|
||||
standalone: true,
|
||||
imports: [RouterLink, RouterLinkActive],
|
||||
templateUrl: './navbar.component.html',
|
||||
styleUrl: './navbar.component.scss',
|
||||
})
|
||||
export class NavbarComponent {
|
||||
menuOpen = false;
|
||||
|
||||
toggleMenu(): void {
|
||||
this.menuOpen = !this.menuOpen;
|
||||
}
|
||||
|
||||
closeMenu(): void {
|
||||
this.menuOpen = false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
<section class="schedule">
|
||||
<div class="container">
|
||||
<div class="schedule-header">
|
||||
<img src="assets/svg/small-flower.svg" alt="" class="schedule-flower" aria-hidden="true">
|
||||
<h2>Today's <span class="text-accent">Program Schedule</span></h2>
|
||||
<p class="section-intro">
|
||||
All times are local (Mountain Time). Every show is free to listen to
|
||||
live at 98.7 FM or via our online stream.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="schedule-list">
|
||||
<div class="schedule-day-label">Monday – Friday</div>
|
||||
<div class="schedule-table">
|
||||
<div *ngFor="let program of programs" class="schedule-row">
|
||||
<div class="schedule-time">{{ program.time }}</div>
|
||||
<div class="schedule-divider"></div>
|
||||
<div class="schedule-details">
|
||||
<h4 class="schedule-title">{{ program.title }}</h4>
|
||||
<div class="schedule-meta">
|
||||
<span class="schedule-host">
|
||||
<span aria-hidden="true">🎙️</span> {{ program.host }}
|
||||
</span>
|
||||
<span class="schedule-genre">{{ program.genre }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="schedule-weekend">
|
||||
<div class="weekend-heading">
|
||||
<img src="assets/svg/small-flower.svg" alt="" class="schedule-flower-sm" aria-hidden="true">
|
||||
<h3>Weekend Programming</h3>
|
||||
</div>
|
||||
<div class="weekend-grid">
|
||||
<div class="weekend-card">
|
||||
<div class="card-day">Saturday</div>
|
||||
<div class="card-programs">
|
||||
<div class="card-item">
|
||||
<strong>9:00 AM</strong> — Country Roads Hour
|
||||
</div>
|
||||
<div class="card-item">
|
||||
<strong>11:00 AM</strong> — Community Hour (call-ins welcome!)
|
||||
</div>
|
||||
<div class="card-item">
|
||||
<strong>2:00 PM</strong> — Afternoon Bluegrass
|
||||
</div>
|
||||
<div class="card-item">
|
||||
<strong>4:00 PM</strong> — Record Request Hour
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="weekend-card">
|
||||
<div class="card-day">Sunday</div>
|
||||
<div class="card-programs">
|
||||
<div class="card-item">
|
||||
<strong>10:00 AM</strong> — Sunday Morning Hymns & Folk
|
||||
</div>
|
||||
<div class="card-item">
|
||||
<strong>12:00 PM</strong> — Gospel & Roots
|
||||
</div>
|
||||
<div class="card-item">
|
||||
<strong>3:00 PM</strong> — The Long Wave (ambient / nature sounds)
|
||||
</div>
|
||||
<div class="card-item">
|
||||
<strong>6:00 PM</strong> — Sunday Sunset Jazz
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
@@ -0,0 +1,173 @@
|
||||
@use '../../styles/variables' as *;
|
||||
@use '../../styles/mixins' as *;
|
||||
|
||||
.schedule {
|
||||
padding: $spacing-3xl 0;
|
||||
background: var(--color-white);
|
||||
}
|
||||
|
||||
.schedule-header {
|
||||
text-align: center;
|
||||
margin-bottom: $spacing-2xl;
|
||||
|
||||
.schedule-flower {
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
margin: 0 auto $spacing-md;
|
||||
opacity: 0.5;
|
||||
}
|
||||
}
|
||||
|
||||
.schedule-list {
|
||||
max-width: 800px;
|
||||
margin: 0 auto $spacing-3xl;
|
||||
}
|
||||
|
||||
.schedule-day-label {
|
||||
text-align: center;
|
||||
font-family: var(--font-heading);
|
||||
font-size: 1.2rem;
|
||||
color: var(--color-primary);
|
||||
margin-bottom: $spacing-md;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.schedule-table {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0;
|
||||
}
|
||||
|
||||
.schedule-row {
|
||||
display: flex;
|
||||
align-items: stretch;
|
||||
padding: $spacing-md 0;
|
||||
border-bottom: 1px solid var(--color-light);
|
||||
transition: background $transition-fast;
|
||||
|
||||
&:hover {
|
||||
background: var(--color-cream);
|
||||
}
|
||||
}
|
||||
|
||||
.schedule-time {
|
||||
width: 100px;
|
||||
flex-shrink: 0;
|
||||
font-family: var(--font-mono);
|
||||
font-size: 0.95rem;
|
||||
color: var(--color-accent);
|
||||
font-weight: 600;
|
||||
padding-right: $spacing-md;
|
||||
text-align: right;
|
||||
padding-top: 2px;
|
||||
}
|
||||
|
||||
.schedule-divider {
|
||||
width: 2px;
|
||||
background: var(--color-accent-muted);
|
||||
margin: 0 $spacing-sm;
|
||||
border-radius: 1px;
|
||||
opacity: 0.4;
|
||||
}
|
||||
|
||||
.schedule-details {
|
||||
flex: 1;
|
||||
padding: $spacing-xs 0;
|
||||
}
|
||||
|
||||
.schedule-title {
|
||||
font-size: 1.05rem;
|
||||
color: var(--color-primary);
|
||||
margin-bottom: $spacing-xs;
|
||||
}
|
||||
|
||||
.schedule-meta {
|
||||
display: flex;
|
||||
gap: $spacing-md;
|
||||
font-size: 0.85rem;
|
||||
color: var(--color-medium);
|
||||
|
||||
.schedule-host {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.schedule-genre {
|
||||
background: var(--color-light);
|
||||
padding: 2px 10px;
|
||||
border-radius: 10px;
|
||||
font-style: italic;
|
||||
}
|
||||
}
|
||||
|
||||
// Weekend
|
||||
.schedule-weekend {
|
||||
margin-top: $spacing-xl;
|
||||
}
|
||||
|
||||
.weekend-heading {
|
||||
text-align: center;
|
||||
margin-bottom: $spacing-lg;
|
||||
|
||||
.schedule-flower-sm {
|
||||
width: 35px;
|
||||
height: 35px;
|
||||
margin: 0 auto $spacing-sm;
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-size: 1.6rem;
|
||||
color: var(--color-primary);
|
||||
}
|
||||
}
|
||||
|
||||
.weekend-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
|
||||
gap: $spacing-lg;
|
||||
}
|
||||
|
||||
.weekend-card {
|
||||
@include card-style;
|
||||
padding: $spacing-xl;
|
||||
background: var(--color-white);
|
||||
|
||||
.card-day {
|
||||
font-family: var(--font-heading);
|
||||
font-size: 1.4rem;
|
||||
font-weight: 700;
|
||||
color: var(--color-accent);
|
||||
margin-bottom: $spacing-md;
|
||||
padding-bottom: $spacing-sm;
|
||||
border-bottom: 2px solid var(--color-light);
|
||||
}
|
||||
|
||||
.card-programs {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: $spacing-sm;
|
||||
}
|
||||
|
||||
.card-item {
|
||||
font-size: 0.95rem;
|
||||
color: var(--color-dark);
|
||||
padding: $spacing-sm;
|
||||
border-radius: $radius-sm;
|
||||
transition: background $transition-fast;
|
||||
|
||||
strong {
|
||||
color: var(--color-primary);
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background: var(--color-cream);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: #{$bp-md - 1px}) {
|
||||
.schedule-time { width: 80px; font-size: 0.85rem; }
|
||||
.weekend-grid { grid-template-columns: 1fr; }
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { NgFor } from '@angular/common';
|
||||
|
||||
interface Program {
|
||||
time: string;
|
||||
title: string;
|
||||
host: string;
|
||||
genre: string;
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'app-schedule',
|
||||
standalone: true,
|
||||
imports: [NgFor],
|
||||
templateUrl: './schedule.component.html',
|
||||
styleUrl: './schedule.component.scss',
|
||||
})
|
||||
export class ScheduleComponent {
|
||||
readonly programs: Program[] = [
|
||||
{ time: '6:00 AM', title: 'Morning Mountain Mist', host: 'Diana Walsh', genre: 'Ambient / Nature' },
|
||||
{ time: '8:00 AM', title: 'Community Roundup', host: 'Tom Breen', genre: 'News / Talk' },
|
||||
{ time: '10:00 AM', title: 'Bluegrass Trails', host: 'Sarah Lynn', genre: 'Bluegrass' },
|
||||
{ time: '12:00 PM', title: 'Lunchtime Jazz', host: 'Mike Darrow', genre: 'Jazz' },
|
||||
{ time: '2:00 PM', title: 'Folk Roots Hour', host: 'Nadia Cole', genre: 'Folk' },
|
||||
{ time: '4:00 PM', title: 'Afternoon Acoustics', host: 'Jen Reeves', genre: 'Acoustic' },
|
||||
{ time: '6:00 PM', title: 'Evening Echoes', host: 'Carlos Mendez', genre: 'Indie / Alternative' },
|
||||
{ time: '8:00 PM', title: 'Classical Mountains', host: 'Elena Cross', genre: 'Classical' },
|
||||
{ time: '10:00 PM', title: 'Night Owl Session', host: 'DJ Kofi', genre: 'Electronic' },
|
||||
{ time: '12:00 AM', title: 'Late Night Jazz', host: 'Mike Darrow', genre: 'Jazz' },
|
||||
];
|
||||
}
|
||||
Reference in New Issue
Block a user