-

-
Signed in as {{nickname}}
+
+
+
+
{{nickname}}
{{email}}
+
-
+
+
Speaker Discord
-
-
- Logout
-
+
+
+ Logout
+
-
+
Report an Issue
-
+
- Mobile App Issue
+ Mobile App Issue
Report a bug or suggest a feature for the app
-
+
- Website Issue
+ Website Issue
Report an issue with us.pycon.org
+
+
diff --git a/src/app/pages/account/account.scss b/src/app/pages/account/account.scss
index 2ce58cbd..e532f05e 100644
--- a/src/app/pages/account/account.scss
+++ b/src/app/pages/account/account.scss
@@ -1,4 +1,63 @@
-img {
- max-width: 140px;
- border-radius: 50%;
+ion-header {
+ background: linear-gradient(180deg, #3B3EA9 0%, #3B3EA9 100%);
+ &::after { display: none; }
+}
+
+ion-toolbar {
+ --background: transparent;
+ --border-color: transparent;
+ --color: #ffffff;
+}
+
+ion-toolbar ion-menu-button {
+ --color: #ffffff;
+}
+
+ion-title {
+ opacity: 0;
+ transition: opacity 0.25s ease;
+
+ &.title-visible {
+ opacity: 1;
+ }
+}
+
+.account-hero {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ padding: 16px 24px 32px;
+ background: linear-gradient(180deg, #3B3EA9 23.5%, #101136 53.29%);
+ color: #fff;
+ text-align: center;
+
+ .account-hero-icon {
+ font-size: 64px;
+ color: #FFD779;
+ margin-bottom: 8px;
+ }
+
+ h1 {
+ margin: 0;
+ font-size: 1.5rem;
+ font-weight: 700;
+ }
+
+ p {
+ margin: 4px 0 0;
+ font-size: 0.85rem;
+ opacity: 0.7;
+
+ code {
+ background: none;
+ font-size: 0.85rem;
+ }
+ }
+}
+
+.account-actions {
+ display: flex;
+ flex-direction: column;
+ gap: 8px;
+ padding: 16px 20px;
}
diff --git a/src/app/pages/account/account.ts b/src/app/pages/account/account.ts
index 31002f77..f01f2ff0 100644
--- a/src/app/pages/account/account.ts
+++ b/src/app/pages/account/account.ts
@@ -1,7 +1,7 @@
-import { AfterViewInit, Component, OnInit } from '@angular/core';
+import { AfterViewInit, Component, OnInit, ViewChild } from '@angular/core';
import { Router } from '@angular/router';
-import { NavController, AlertController } from '@ionic/angular';
+import { IonContent, NavController, AlertController } from '@ionic/angular';
import { InAppBrowser, DefaultWebViewOptions } from '@capacitor/inappbrowser';
import { AppComponent } from '../../app.component';
@@ -16,6 +16,8 @@ import { environment } from '../../../environments/environment';
styleUrls: ['./account.scss'],
})
export class AccountPage implements OnInit, AfterViewInit {
+ @ViewChild(IonContent) content: IonContent;
+ showTitle = false;
email: string;
nickname: string;
isSpeaker: boolean = false;
@@ -29,6 +31,10 @@ export class AccountPage implements OnInit, AfterViewInit {
public liveUpdateService: LiveUpdateService,
) { }
+ onScroll(event: any) {
+ this.showTitle = event.detail.scrollTop > 100;
+ }
+
ngOnInit() {
this.app.fetchFeatures();
}
diff --git a/src/app/pages/coc/coc.page.html b/src/app/pages/coc/coc.page.html
index ba7a5f37..1effcb41 100644
--- a/src/app/pages/coc/coc.page.html
+++ b/src/app/pages/coc/coc.page.html
@@ -1,14 +1,14 @@
-
+
1
- Code of Conduct
+ Code of Conduct
-
+
diff --git a/src/app/pages/coc/coc.page.scss b/src/app/pages/coc/coc.page.scss
index 2c7b19c6..b9fcc973 100644
--- a/src/app/pages/coc/coc.page.scss
+++ b/src/app/pages/coc/coc.page.scss
@@ -1,5 +1,29 @@
+ion-header {
+ background: linear-gradient(180deg, #3B3EA9 0%, #3B3EA9 100%);
+ &::after { display: none; }
+}
+
+ion-toolbar {
+ --background: transparent;
+ --border-color: transparent;
+ --color: #ffffff;
+}
+
+ion-toolbar ion-menu-button {
+ --color: #ffffff;
+}
+
+ion-title {
+ opacity: 0;
+ transition: opacity 0.25s ease;
+
+ &.title-visible {
+ opacity: 1;
+ }
+}
+
.coc-hero {
- padding: 48px 24px 32px;
+ padding: 16px 24px 32px;
background: linear-gradient(180deg, #3B3EA9 23.5%, #101136 53.29%);
color: #fff;
text-align: center;
diff --git a/src/app/pages/coc/coc.page.ts b/src/app/pages/coc/coc.page.ts
index 85784233..8ca3db66 100644
--- a/src/app/pages/coc/coc.page.ts
+++ b/src/app/pages/coc/coc.page.ts
@@ -1,4 +1,5 @@
-import { Component, OnInit, ChangeDetectorRef } from '@angular/core';
+import { Component, OnInit, ChangeDetectorRef, ViewChild } from '@angular/core';
+import { IonContent } from '@ionic/angular';
import { ConferenceData } from '../../providers/conference-data';
import { LiveUpdateService } from '../../providers/live-update.service';
@@ -8,7 +9,9 @@ import { LiveUpdateService } from '../../providers/live-update.service';
styleUrls: ['./coc.page.scss'],
})
export class CocPage implements OnInit {
+ @ViewChild(IonContent) ionContent: IonContent;
content: any = '';
+ showTitle = false;
constructor(
private confData: ConferenceData,
@@ -16,6 +19,10 @@ export class CocPage implements OnInit {
public liveUpdateService: LiveUpdateService,
) {}
+ onScroll(event: any) {
+ this.showTitle = event.detail.scrollTop > 100;
+ }
+
ngOnInit() {
this.confData.getContent().subscribe((content: any) => {
this.content = content;
diff --git a/src/app/pages/help/help.page.html b/src/app/pages/help/help.page.html
index 6193a8d7..1e2cd732 100644
--- a/src/app/pages/help/help.page.html
+++ b/src/app/pages/help/help.page.html
@@ -3,11 +3,17 @@
-
Help & Safety
+
Help & Safety
-
+
+
+
+
Help & Safety
+
Resources for a safe and welcoming conference
+
+
At the Conference
diff --git a/src/app/pages/help/help.page.scss b/src/app/pages/help/help.page.scss
index e69de29b..c5ac4160 100644
--- a/src/app/pages/help/help.page.scss
+++ b/src/app/pages/help/help.page.scss
@@ -0,0 +1,51 @@
+ion-header {
+ background: linear-gradient(180deg, #3B3EA9 0%, #3B3EA9 100%);
+ &::after { display: none; }
+}
+
+ion-toolbar {
+ --background: transparent;
+ --border-color: transparent;
+ --color: #ffffff;
+}
+
+ion-toolbar ion-menu-button {
+ --color: #ffffff;
+}
+
+ion-title {
+ opacity: 0;
+ transition: opacity 0.25s ease;
+
+ &.title-visible {
+ opacity: 1;
+ }
+}
+
+.page-hero {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ padding: 16px 24px 32px;
+ background: linear-gradient(180deg, #3B3EA9 23.5%, #101136 53.29%);
+ color: #fff;
+ text-align: center;
+
+ .page-hero-icon {
+ font-size: 40px;
+ color: #FFD779;
+ margin-bottom: 10px;
+ }
+
+ h1 {
+ margin: 0;
+ font-size: 1.6rem;
+ font-weight: 700;
+ }
+
+ p {
+ margin: 6px 0 0;
+ font-size: 0.9rem;
+ opacity: 0.8;
+ }
+}
diff --git a/src/app/pages/help/help.page.ts b/src/app/pages/help/help.page.ts
index c898f327..2c408e05 100644
--- a/src/app/pages/help/help.page.ts
+++ b/src/app/pages/help/help.page.ts
@@ -1,4 +1,5 @@
-import { Component } from '@angular/core';
+import { Component, ViewChild } from '@angular/core';
+import { IonContent } from '@ionic/angular';
@Component({
selector: 'app-help',
@@ -6,6 +7,13 @@ import { Component } from '@angular/core';
styleUrls: ['./help.page.scss'],
})
export class HelpPage {
+ @ViewChild(IonContent) content: IonContent;
+ showTitle = false;
+
+ onScroll(event: any) {
+ this.showTitle = event.detail.scrollTop > 100;
+ }
+
openUrl(url: string) {
window.open(url, '_system', 'location=yes');
}
diff --git a/src/app/pages/job-listings/job-listings.page.html b/src/app/pages/job-listings/job-listings.page.html
index c517627f..eed5e86d 100644
--- a/src/app/pages/job-listings/job-listings.page.html
+++ b/src/app/pages/job-listings/job-listings.page.html
@@ -1,28 +1,28 @@
-
+
1
- Job Listings
+ Job Listings
-
+
+
+
+
Job Listings
+
Opportunities from PyCon US sponsors
+
+
0" class="search-toolbar">
-
-
- Job opportunities from PyCon US sponsors hiring in the Python community.
-
-
-
No job listings have been posted yet. Check back closer to the conference!
diff --git a/src/app/pages/job-listings/job-listings.page.scss b/src/app/pages/job-listings/job-listings.page.scss
index f5e38b98..6836cb19 100644
--- a/src/app/pages/job-listings/job-listings.page.scss
+++ b/src/app/pages/job-listings/job-listings.page.scss
@@ -1,7 +1,57 @@
-.page-intro {
- font-size: 0.9rem;
- opacity: 0.7;
- margin-bottom: 0;
+ion-header {
+ background: linear-gradient(180deg, #3B3EA9 0%, #3B3EA9 100%);
+ &::after { display: none; }
+}
+
+ion-toolbar {
+ --background: transparent;
+ --border-color: transparent;
+ --color: #ffffff;
+}
+
+ion-toolbar ion-menu-button {
+ --color: #ffffff;
+}
+
+ion-title {
+ opacity: 0;
+ transition: opacity 0.25s ease;
+
+ &.title-visible {
+ opacity: 1;
+ }
+}
+
+.page-hero {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ padding: 16px 24px 32px;
+ background: linear-gradient(180deg, #3B3EA9 23.5%, #101136 53.29%);
+ color: #fff;
+ text-align: center;
+
+ .page-hero-icon {
+ font-size: 40px;
+ color: #25C8EB;
+ margin-bottom: 10px;
+ }
+
+ h1 {
+ margin: 0;
+ font-size: 1.6rem;
+ font-weight: 700;
+ }
+
+ p {
+ margin: 6px 0 0;
+ font-size: 0.9rem;
+ opacity: 0.8;
+ }
+}
+
+.search-toolbar {
+ margin-top: 12px;
}
.listings-container {
diff --git a/src/app/pages/job-listings/job-listings.page.ts b/src/app/pages/job-listings/job-listings.page.ts
index 6ae7d0f9..1629f60f 100644
--- a/src/app/pages/job-listings/job-listings.page.ts
+++ b/src/app/pages/job-listings/job-listings.page.ts
@@ -1,4 +1,5 @@
-import { Component, OnInit, ChangeDetectorRef } from '@angular/core';
+import { Component, OnInit, ChangeDetectorRef, ViewChild } from '@angular/core';
+import { IonContent } from '@ionic/angular';
import { ConferenceData } from '../../providers/conference-data';
import { LiveUpdateService } from '../../providers/live-update.service';
@@ -9,6 +10,8 @@ import { LiveUpdateService } from '../../providers/live-update.service';
styleUrls: ['./job-listings.page.scss'],
})
export class JobListingsPage implements OnInit {
+ @ViewChild(IonContent) content: IonContent;
+ showTitle = false;
allListings: any[] = [];
listings: any[] = [];
searchText: string = '';
@@ -19,6 +22,10 @@ export class JobListingsPage implements OnInit {
public liveUpdateService: LiveUpdateService,
) {}
+ onScroll(event: any) {
+ this.showTitle = event.detail.scrollTop > 100;
+ }
+
processListings(raw: any[]): any[] {
return raw.map(listing => {
return {
diff --git a/src/app/pages/keynote-speakers/keynote-speakers-routing.module.ts b/src/app/pages/keynote-speakers/keynote-speakers-routing.module.ts
new file mode 100644
index 00000000..ddef1729
--- /dev/null
+++ b/src/app/pages/keynote-speakers/keynote-speakers-routing.module.ts
@@ -0,0 +1,11 @@
+import { NgModule } from '@angular/core';
+import { Routes, RouterModule } from '@angular/router';
+import { KeynoteSpeakersPage } from './keynote-speakers.page';
+
+const routes: Routes = [{ path: '', component: KeynoteSpeakersPage }];
+
+@NgModule({
+ imports: [RouterModule.forChild(routes)],
+ exports: [RouterModule],
+})
+export class KeynoteSpeakersPageRoutingModule {}
diff --git a/src/app/pages/keynote-speakers/keynote-speakers.module.ts b/src/app/pages/keynote-speakers/keynote-speakers.module.ts
new file mode 100644
index 00000000..f103fe72
--- /dev/null
+++ b/src/app/pages/keynote-speakers/keynote-speakers.module.ts
@@ -0,0 +1,11 @@
+import { NgModule } from '@angular/core';
+import { CommonModule } from '@angular/common';
+import { IonicModule } from '@ionic/angular';
+import { KeynoteSpeakersPageRoutingModule } from './keynote-speakers-routing.module';
+import { KeynoteSpeakersPage } from './keynote-speakers.page';
+
+@NgModule({
+ imports: [CommonModule, IonicModule, KeynoteSpeakersPageRoutingModule],
+ declarations: [KeynoteSpeakersPage]
+})
+export class KeynoteSpeakersPageModule {}
diff --git a/src/app/pages/keynote-speakers/keynote-speakers.page.html b/src/app/pages/keynote-speakers/keynote-speakers.page.html
new file mode 100644
index 00000000..e25b09a4
--- /dev/null
+++ b/src/app/pages/keynote-speakers/keynote-speakers.page.html
@@ -0,0 +1,51 @@
+
+
+
+
+ 1
+
+ Keynote Speakers
+
+
+
+
+
+
+
Keynote Speakers
+
PyCon US 2026
+
+
+
+
+
+
![]()
+
+ {{ speaker.name }}
+ {{ speaker.bio }}
+
+
+
+ {{ speaker.session.name }}
+ {{ speaker.session.day }} {{ speaker.session.timeStart }} — {{ speaker.session.location }}
+
+
+
+
+
+
+
+
+
+
![]()
+
{{ member.name }}
+
+
+ {{ steeringCouncil.name }}
+ {{ steeringCouncil.bio }}
+
+
+
+
+
diff --git a/src/app/pages/keynote-speakers/keynote-speakers.page.scss b/src/app/pages/keynote-speakers/keynote-speakers.page.scss
new file mode 100644
index 00000000..eab42019
--- /dev/null
+++ b/src/app/pages/keynote-speakers/keynote-speakers.page.scss
@@ -0,0 +1,150 @@
+ion-header {
+ background: linear-gradient(180deg, #3B3EA9 0%, #3B3EA9 100%);
+ &::after { display: none; }
+}
+
+ion-toolbar {
+ --background: transparent;
+ --border-color: transparent;
+ --color: #ffffff;
+}
+
+ion-toolbar ion-menu-button {
+ --color: #ffffff;
+}
+
+ion-title {
+ opacity: 0;
+ transition: opacity 0.25s ease;
+
+ &.title-visible {
+ opacity: 1;
+ }
+}
+
+.ks-hero {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ padding: 16px 24px 48px;
+ background: linear-gradient(180deg, #3B3EA9 23.5%, #101136 53.29%);
+ color: #fff;
+ text-align: center;
+
+ .ks-hero-icon {
+ font-size: 56px;
+ color: #FFD779;
+ margin-bottom: 12px;
+ }
+
+ h1 {
+ margin: 0;
+ font-size: 1.6rem;
+ font-weight: 700;
+ }
+
+ p {
+ margin: 8px 0 0;
+ font-size: 0.95rem;
+ opacity: 0.85;
+ }
+}
+
+.ks-card {
+ margin: 0 20px 16px;
+ border-radius: 16px;
+ box-shadow: 0 8px 32px rgba(16, 17, 54, 0.15);
+
+ &.ks-card-first {
+ margin-top: -24px;
+ position: relative;
+ z-index: 1;
+ }
+
+ ion-card-content {
+ padding: 24px;
+ }
+
+ h2 {
+ font-size: 1.15rem;
+ font-weight: 700;
+ margin: 0 0 8px;
+ text-align: center;
+ }
+
+ p {
+ font-size: 0.95rem;
+ line-height: 1.5;
+ margin: 0;
+ color: var(--ion-text-color);
+ }
+}
+
+.ks-speaker-photo-wrap {
+ display: flex;
+ justify-content: center;
+ margin-bottom: 16px;
+}
+
+.ks-speaker-photo {
+ width: 120px;
+ height: 120px;
+ border-radius: 50%;
+ object-fit: cover;
+ border: 3px solid #3B3EA9;
+}
+
+.ks-card-council {
+ ion-card-content {
+ padding: 24px;
+ }
+}
+
+.ks-session-link {
+ --padding-start: 12px;
+ --background: var(--ion-color-step-50, #f5f5f5);
+ --border-radius: 10px;
+ margin-top: 12px;
+
+ h3 {
+ font-size: 0.9rem;
+ font-weight: 600;
+ }
+
+ p {
+ font-size: 0.8rem;
+ color: var(--ion-color-medium);
+ margin: 0;
+ }
+}
+
+.ks-council-photos {
+ display: flex;
+ justify-content: center;
+ gap: 8px;
+ margin-bottom: 16px;
+}
+
+.ks-council-member {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ gap: 2px;
+ width: 56px;
+}
+
+.ks-council-photo {
+ width: 48px;
+ height: 48px;
+ border-radius: 50%;
+ object-fit: cover;
+ border: 2px solid #3B3EA9;
+}
+
+.ks-council-name {
+ font-size: 0.6rem;
+ color: var(--ion-color-medium);
+ text-align: center;
+ max-width: 56px;
+ line-height: 1.2;
+}
diff --git a/src/app/pages/keynote-speakers/keynote-speakers.page.ts b/src/app/pages/keynote-speakers/keynote-speakers.page.ts
new file mode 100644
index 00000000..60945f20
--- /dev/null
+++ b/src/app/pages/keynote-speakers/keynote-speakers.page.ts
@@ -0,0 +1,99 @@
+import { Component, ViewChild, OnInit } from '@angular/core';
+import { IonContent } from '@ionic/angular';
+import { LiveUpdateService } from '../../providers/live-update.service';
+import { ConferenceData } from '../../providers/conference-data';
+
+interface KeynoteSpeaker {
+ name: string;
+ photo: string;
+ bio: string;
+ session?: any;
+}
+
+interface SteeringCouncilMember {
+ name: string;
+ photo: string;
+}
+
+interface SteeringCouncil {
+ name: string;
+ members: SteeringCouncilMember[];
+ bio: string;
+}
+
+@Component({
+ selector: 'app-keynote-speakers',
+ templateUrl: './keynote-speakers.page.html',
+ styleUrls: ['./keynote-speakers.page.scss'],
+})
+export class KeynoteSpeakersPage implements OnInit {
+ @ViewChild(IonContent) content: IonContent;
+ showTitle = false;
+
+ speakers: KeynoteSpeaker[] = [
+ {
+ name: 'Lin Qiao',
+ photo: 'https://pycon-assets.s3.amazonaws.com/2026/media/images/lin_qiao.original.jpg',
+ bio: 'Lin Qiao is the CEO and co-founder of global AI inference cloud and infrastructure platform Fireworks AI, enables teams like Cursor, Uber, DoorDash, and Shopify to build, tune, and scale highly optimized generative AI applications. Prior to founding Fireworks, Lin was the co-creator and head of Meta\'s PyTorch.',
+ },
+ {
+ name: 'amanda casari',
+ photo: 'https://pycon-assets.s3.amazonaws.com/2026/media/images/amcasari-headshot.original.png',
+ bio: 'amanda casari is an engineer and researcher who has worked in many technical and socio-technical disciplines for over 20 years, including developer relations, product management, data science, and underwater robotics. amanda was named an External Faculty member of the Vermont Complex Systems Center in 2021 and co-authored Feature Engineering for Machine Learning Principles and Techniques for Data Scientists for O\'Reilly.',
+ },
+ {
+ name: 'Tim Schilling',
+ photo: 'https://pycon-assets.s3.amazonaws.com/2026/media/images/Tim_Schilling.original.jpg',
+ bio: 'I\'m a software engineer that loves Django and our community. I\'m on the Django Steering Council, a cofounder of Djangonaut Space and an admin of Django Commons. I\'ve been helping maintain django-debug-toolbar and a few other packages.',
+ },
+ {
+ name: 'Rachell Calhoun',
+ photo: 'https://pycon-assets.s3.amazonaws.com/2026/media/images/rachell_calhoun.original.jpg',
+ bio: 'I\'m Rachell, co-founder of Djangonaut Space and a Django developer. I love building practical, user-friendly tools and creating communities where people walk away with new skills, confidence, and some new friends. I\'ve organized Django Girls workshops across multiple countries and continents for over 10 years.',
+ },
+ {
+ name: 'Pablo Galindo Salgado',
+ photo: 'https://pycon-assets.s3.amazonaws.com/2026/media/images/Pablo_Galindo_Salgado.original.jpg',
+ bio: 'Pablo Galindo Salgado works in the Python team of Hudson River Trading. He is a CPython core developer and a Theoretical Physicist specializing in general relativity and black hole physics. He is currently serving on the Python Steering Council in his 6th term and he is the release manager for Python 3.10 and 3.11.',
+ },
+ ];
+
+ steeringCouncil: SteeringCouncil = {
+ name: 'Python Steering Council',
+ members: [
+ { name: 'Barry Warsaw', photo: 'https://pycon-assets.s3.amazonaws.com/2026/media/images/Barry_PyCon.max-165x165.jpg' },
+ { name: 'Donghee Na', photo: 'https://pycon-assets.s3.amazonaws.com/2026/media/images/donghee_na.max-165x165.jpg' },
+ { name: 'Pablo Galindo Salgado', photo: 'https://pycon-assets.s3.amazonaws.com/2026/media/images/Pablo_Galindo_Salgado.max-165x165.jpg' },
+ { name: 'Savannah Ostrowski', photo: 'https://pycon-assets.s3.amazonaws.com/2026/media/images/savannah.max-165x165.jpg' },
+ { name: 'Thomas Wouters', photo: 'https://pycon-assets.s3.amazonaws.com/2026/media/images/Thomas_Wouters.max-165x165.jpg' },
+ ],
+ bio: 'The Python Steering Council is a 5-person elected committee that assumes a mandate to maintain the quality and stability of the Python language and CPython interpreter, improve the contributor experience, formalize and maintain a relationship between the Python core team and the PSF, establish decision making processes for Python Enhancement Proposals, seek consensus among contributors and the Python core team, and resolve decisions and disputes in decision making among the language.',
+ };
+
+ constructor(
+ public liveUpdateService: LiveUpdateService,
+ private confData: ConferenceData,
+ ) {}
+
+ ngOnInit() {
+ this.confData.load().subscribe((data: any) => {
+ if (data?.sessions) {
+ const keynoteSessions = data.sessions.filter(
+ (s: any) => s.track === 'Keynote' || s.tracks?.includes('keynote')
+ );
+ this.speakers.forEach(speaker => {
+ const match = keynoteSessions.find(
+ (s: any) => s.name?.toLowerCase().includes(speaker.name.toLowerCase())
+ );
+ if (match) {
+ speaker.session = match;
+ }
+ });
+ }
+ });
+ }
+
+ onScroll(event: any) {
+ this.showTitle = event.detail.scrollTop > 100;
+ }
+}
diff --git a/src/app/pages/lightning-talks/lightning-talks.page.html b/src/app/pages/lightning-talks/lightning-talks.page.html
index 2254255c..4b30c343 100644
--- a/src/app/pages/lightning-talks/lightning-talks.page.html
+++ b/src/app/pages/lightning-talks/lightning-talks.page.html
@@ -1,14 +1,14 @@
-
+
1
- Lightning Talks
+ Lightning Talks
-
+
Lightning Talks
diff --git a/src/app/pages/lightning-talks/lightning-talks.page.scss b/src/app/pages/lightning-talks/lightning-talks.page.scss
index 916464a4..800a3be2 100644
--- a/src/app/pages/lightning-talks/lightning-talks.page.scss
+++ b/src/app/pages/lightning-talks/lightning-talks.page.scss
@@ -1,8 +1,32 @@
+ion-header {
+ background: linear-gradient(180deg, #3B3EA9 0%, #3B3EA9 100%);
+ &::after { display: none; }
+}
+
+ion-toolbar {
+ --background: transparent;
+ --border-color: transparent;
+ --color: #ffffff;
+}
+
+ion-toolbar ion-menu-button {
+ --color: #ffffff;
+}
+
+ion-title {
+ opacity: 0;
+ transition: opacity 0.25s ease;
+
+ &.title-visible {
+ opacity: 1;
+ }
+}
+
.lt-hero {
display: flex;
flex-direction: column;
align-items: center;
- padding: 48px 24px 32px;
+ padding: 16px 24px 32px;
background: linear-gradient(180deg, #3B3EA9 23.5%, #101136 53.29%);
color: #fff;
text-align: center;
diff --git a/src/app/pages/lightning-talks/lightning-talks.page.ts b/src/app/pages/lightning-talks/lightning-talks.page.ts
index 2c83982f..e974ed0d 100644
--- a/src/app/pages/lightning-talks/lightning-talks.page.ts
+++ b/src/app/pages/lightning-talks/lightning-talks.page.ts
@@ -1,4 +1,5 @@
-import { Component } from '@angular/core';
+import { Component, ViewChild } from '@angular/core';
+import { IonContent } from '@ionic/angular';
import { LiveUpdateService } from '../../providers/live-update.service';
@Component({
@@ -7,8 +8,15 @@ import { LiveUpdateService } from '../../providers/live-update.service';
styleUrls: ['./lightning-talks.page.scss'],
})
export class LightningTalksPage {
+ @ViewChild(IonContent) content: IonContent;
+ showTitle = false;
+
constructor(public liveUpdateService: LiveUpdateService) {}
+ onScroll(event: any) {
+ this.showTitle = event.detail.scrollTop > 100;
+ }
+
signUp() {
window.open('https://us.pycon.org/2026/events/lightning-talks/', '_system', 'location=yes');
}
diff --git a/src/app/pages/now/now.page.html b/src/app/pages/now/now.page.html
index 03c4f068..1468c7c3 100644
--- a/src/app/pages/now/now.page.html
+++ b/src/app/pages/now/now.page.html
@@ -1,17 +1,23 @@
-
+
-
+
- Now
+ Now & Next
-
+
+
+
+
Now & Next
+
What's happening at PyCon US right now
+
+
No sessions today
diff --git a/src/app/pages/now/now.page.scss b/src/app/pages/now/now.page.scss
index e8718372..660ca443 100644
--- a/src/app/pages/now/now.page.scss
+++ b/src/app/pages/now/now.page.scss
@@ -1,3 +1,55 @@
+ion-header {
+ background: linear-gradient(180deg, #3B3EA9 0%, #3B3EA9 100%);
+ &::after { display: none; }
+}
+
+ion-toolbar {
+ --background: transparent;
+ --border-color: transparent;
+ --color: #ffffff;
+}
+
+ion-toolbar ion-menu-button {
+ --color: #ffffff;
+}
+
+ion-title {
+ opacity: 0;
+ transition: opacity 0.25s ease;
+
+ &.title-visible {
+ opacity: 1;
+ }
+}
+
+.page-hero {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ padding: 16px 24px 32px;
+ background: linear-gradient(180deg, #3B3EA9 23.5%, #101136 53.29%);
+ color: #fff;
+ text-align: center;
+
+ .page-hero-icon {
+ font-size: 40px;
+ color: #DD04D2;
+ margin-bottom: 10px;
+ }
+
+ h1 {
+ margin: 0;
+ font-size: 1.6rem;
+ font-weight: 700;
+ }
+
+ p {
+ margin: 6px 0 0;
+ font-size: 0.9rem;
+ opacity: 0.8;
+ }
+}
+
.section {
padding: 0 0 1em;
}
diff --git a/src/app/pages/now/now.page.ts b/src/app/pages/now/now.page.ts
index e7ba7d64..69dc9516 100644
--- a/src/app/pages/now/now.page.ts
+++ b/src/app/pages/now/now.page.ts
@@ -1,4 +1,5 @@
-import { Component, OnInit, OnDestroy } from '@angular/core';
+import { Component, OnInit, OnDestroy, ViewChild } from '@angular/core';
+import { IonContent } from '@ionic/angular';
import { ConferenceData } from '../../providers/conference-data';
import { environment } from '../../../environments/environment';
@@ -8,6 +9,8 @@ import { environment } from '../../../environments/environment';
styleUrls: ['./now.page.scss'],
})
export class NowPage implements OnInit, OnDestroy {
+ @ViewChild(IonContent) content: IonContent;
+ showTitle = false;
nowSessions: any[] = [];
nextSessions: any[] = [];
nextTime: string = '';
@@ -17,6 +20,10 @@ export class NowPage implements OnInit, OnDestroy {
constructor(private confData: ConferenceData) {}
+ onScroll(event: any) {
+ this.showTitle = event.detail.scrollTop > 100;
+ }
+
ngOnInit() {
this.refresh();
this.refreshInterval = setInterval(() => this.refresh(), 60000);
diff --git a/src/app/pages/schedule-list/schedule-list.page.html b/src/app/pages/schedule-list/schedule-list.page.html
index 90d38cb2..a8611fd6 100644
--- a/src/app/pages/schedule-list/schedule-list.page.html
+++ b/src/app/pages/schedule-list/schedule-list.page.html
@@ -1,19 +1,24 @@
-
+
-
+
1
-
- {{trackName | trackName : 'plural'}}
-
+ {{trackName | trackName : 'plural'}}
New track!
-
+
+
+
+
{{trackName | trackName : 'plural'}}
+
Browse presentations in this track
+
Attendee-organized sessions
+
+
diff --git a/src/app/pages/schedule-list/schedule-list.page.scss b/src/app/pages/schedule-list/schedule-list.page.scss
index dc395c59..9193d9d0 100644
--- a/src/app/pages/schedule-list/schedule-list.page.scss
+++ b/src/app/pages/schedule-list/schedule-list.page.scss
@@ -1,3 +1,55 @@
+ion-header {
+ background: linear-gradient(180deg, #3B3EA9 0%, #3B3EA9 100%);
+ &::after { display: none; }
+}
+
+ion-toolbar {
+ --background: transparent;
+ --border-color: transparent;
+ --color: #ffffff;
+}
+
+ion-toolbar ion-menu-button {
+ --color: #ffffff;
+}
+
+ion-title {
+ opacity: 0;
+ transition: opacity 0.25s ease;
+
+ &.title-visible {
+ opacity: 1;
+ }
+}
+
+.page-hero {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ padding: 16px 24px 32px;
+ background: linear-gradient(180deg, #3B3EA9 23.5%, #101136 53.29%);
+ color: #fff;
+ text-align: center;
+
+ .page-hero-icon {
+ font-size: 40px;
+ color: #FFD779;
+ margin-bottom: 10px;
+ }
+
+ h1 {
+ margin: 0;
+ font-size: 1.6rem;
+ font-weight: 700;
+ }
+
+ p {
+ margin: 6px 0 0;
+ font-size: 0.9rem;
+ opacity: 0.8;
+ }
+}
+
::ng-deep ion-title.track-title {
font-size: 0.95rem;
diff --git a/src/app/pages/schedule-list/schedule-list.page.ts b/src/app/pages/schedule-list/schedule-list.page.ts
index e8ddfbf7..a2a63a8e 100644
--- a/src/app/pages/schedule-list/schedule-list.page.ts
+++ b/src/app/pages/schedule-list/schedule-list.page.ts
@@ -1,7 +1,7 @@
import { Component, ChangeDetectorRef, ViewChild, OnInit } from '@angular/core';
import { ConferenceData } from '../../providers/conference-data';
import { ActivatedRoute } from '@angular/router';
-import { Config, InfiniteScrollCustomEvent, LoadingController } from '@ionic/angular';
+import { Config, IonContent, InfiniteScrollCustomEvent, LoadingController } from '@ionic/angular';
import { InAppBrowser, DefaultWebViewOptions } from '@capacitor/inappbrowser';
import { LiveUpdateService } from '../../providers/live-update.service';
import { UserData } from '../../providers/user-data';
@@ -23,6 +23,8 @@ const slugify = str =>
export class ScheduleListPage implements OnInit {
// Get a reference to the search bar
@ViewChild('search') search : any;
+ @ViewChild(IonContent) content: IonContent;
+ showTitle = false;
trackName: string;
trackSlug: string;
excludeTracks: any[] = [];
@@ -51,6 +53,10 @@ export class ScheduleListPage implements OnInit {
) { }
+ onScroll(event: any) {
+ this.showTitle = event.detail.scrollTop > 100;
+ }
+
updateSessions() {
this.confData.getSessions(this.sessionQueryText, this.excludeTracks).subscribe((sessions: any[]) => {
this.sessions = sessions;
diff --git a/src/app/pages/session-detail/session-detail.html b/src/app/pages/session-detail/session-detail.html
index 65579133..b8424b07 100644
--- a/src/app/pages/session-detail/session-detail.html
+++ b/src/app/pages/session-detail/session-detail.html
@@ -1,4 +1,4 @@
-
+
@@ -9,7 +9,7 @@
-
+
@@ -17,21 +17,23 @@
-
{{session.name}}
+
+
{{session.name}}
-
-
{{track | trackName : 'long'}}
-
- New track!
-
-
En Español
-
Pre-registration required
+
+ {{track | trackName : 'long'}}
+
+ New track!
+
+ En Español
+ Pre-registration required
+
-
0" class="session-speakers-section">
-
-
-
-
-
- {{speaker.name}}
- Speaker
-
-
-
+
+
+
![]()
+
+
{{keynoteData.name}}
+
{{keynoteData.bio}}
+
+
-
-
![]()
-
+
0" class="session-speakers-section">
+
+
+
+
+
+ {{speaker.name}}
+ Speaker
+
+
+
+
+
+
![]()
+
-
diff --git a/src/app/pages/session-detail/session-detail.scss b/src/app/pages/session-detail/session-detail.scss
index e06ca4df..814687f7 100644
--- a/src/app/pages/session-detail/session-detail.scss
+++ b/src/app/pages/session-detail/session-detail.scss
@@ -1,5 +1,34 @@
-.session-detail-content {
- padding: 20px 16px;
+/*
+ * Session Detail — PyCon 2026 Theme
+ */
+
+ion-header {
+ background: linear-gradient(180deg, #3B3EA9 0%, #3B3EA9 100%);
+
+ &::after {
+ display: none;
+ }
+}
+
+ion-toolbar {
+ --background: transparent;
+ --border-color: transparent;
+ --color: #ffffff;
+}
+
+ion-toolbar ion-back-button,
+ion-toolbar ion-button {
+ --color: #ffffff;
+ color: #ffffff;
+}
+
+/*
+ * Hero section — gradient continuation from header
+ */
+
+.session-hero {
+ background: linear-gradient(180deg, #3B3EA9 23.5%, #101136 53.29%);
+ padding: 0 20px 40px;
}
.session-title {
@@ -7,34 +36,88 @@
font-weight: 700;
line-height: 1.25;
margin: 0 0 12px;
+ color: #ffffff;
}
.session-badges {
display: flex;
flex-wrap: wrap;
gap: 6px;
- margin-bottom: 16px;
+
+ .prereg-badge {
+ background-color: rgba(255, 255, 255, 0.2);
+ color: #ffffff;
+ border: 1px solid rgba(255, 255, 255, 0.5);
+ }
+
+ .spanish-badge {
+ background-color: rgba(255, 255, 255, 0.2);
+ color: #ffffff;
+ }
+
+ .new-badge {
+ background-color: rgba(255, 255, 255, 0.2);
+ color: #ffffff;
+ }
+}
+
+/*
+ * Keynote speaker card
+ */
+
+.keynote-speaker-card {
+ display: flex;
+ gap: 16px;
+ padding: 16px 20px;
+ margin: 0 0 8px;
+ align-items: flex-start;
+
+ .keynote-photo {
+ width: 80px;
+ height: 80px;
+ border-radius: 12px;
+ object-fit: cover;
+ flex-shrink: 0;
+ }
+
+ .keynote-info {
+ flex: 1;
+
+ h3 {
+ margin: 0 0 4px;
+ font-size: 1rem;
+ font-weight: 700;
+ }
+
+ p {
+ margin: 0;
+ font-size: 0.85rem;
+ line-height: 1.4;
+ color: var(--ion-color-medium);
+ }
+ }
}
+/*
+ * Meta card — overlaps the gradient
+ */
+
.session-meta-card {
- background: var(--ion-color-step-50, #f5f5f5);
- border-radius: 12px;
- padding: 14px 16px;
- margin-bottom: 20px;
+ background: var(--ion-background-color, #ffffff);
+ border-radius: 16px;
+ padding: 16px 18px;
+ margin: -20px 16px 0;
+ position: relative;
+ z-index: 1;
display: flex;
flex-direction: column;
gap: 10px;
-}
-
-// When image or description directly follows meta-card (no speakers section),
-// add extra top spacing for visual breathing room
-.session-meta-card + .session-image-container,
-.session-meta-card + .session-description {
- margin-top: 4px;
+ box-shadow: 0 4px 16px rgba(16, 17, 54, 0.1);
}
:host-context(.dark-theme) .session-meta-card {
background: var(--ion-color-step-100, #1a1a1a);
+ box-shadow: 0 4px 16px rgba(0, 0, 0, 0.3);
}
.meta-row {
@@ -45,11 +128,23 @@
ion-icon {
font-size: 1.2em;
- color: var(--ion-color-step-500, #808080);
+ color: #3B3EA9;
flex-shrink: 0;
}
}
+:host-context(.dark-theme) .meta-row ion-icon {
+ color: #8b8fd4;
+}
+
+/*
+ * Body content below the card
+ */
+
+.session-body {
+ padding: 16px 16px 0;
+}
+
.session-speakers-section {
margin-bottom: 20px;
diff --git a/src/app/pages/session-detail/session-detail.ts b/src/app/pages/session-detail/session-detail.ts
index 2555364a..ee7a363e 100644
--- a/src/app/pages/session-detail/session-detail.ts
+++ b/src/app/pages/session-detail/session-detail.ts
@@ -17,8 +17,33 @@ export class SessionDetailPage {
session: any;
isFavorite = false;
isOpenSpace = false;
+ isKeynote = false;
+ keynoteData: any = null;
defaultHref = '';
+ private keynoteSpeakers: Record
= {
+ 'Lin Qiao': {
+ photo: 'https://pycon-assets.s3.amazonaws.com/2026/media/images/lin_qiao.original.jpg',
+ bio: 'Lin Qiao is the CEO and co-founder of global AI inference cloud and infrastructure platform Fireworks AI, enables teams like Cursor, Uber, DoorDash, and Shopify to build, tune, and scale highly optimized generative AI applications. Prior to founding Fireworks, Lin was the co-creator and head of Meta\'s PyTorch.',
+ },
+ 'amanda casari': {
+ photo: 'https://pycon-assets.s3.amazonaws.com/2026/media/images/amcasari-headshot.original.png',
+ bio: 'amanda casari is an engineer and researcher who has worked in many technical and socio-technical disciplines for over 20 years, including developer relations, product management, data science, and underwater robotics.',
+ },
+ 'Tim Schilling': {
+ photo: 'https://pycon-assets.s3.amazonaws.com/2026/media/images/Tim_Schilling.original.jpg',
+ bio: 'A software engineer that loves Django and our community. On the Django Steering Council, a cofounder of Djangonaut Space and an admin of Django Commons.',
+ },
+ 'Rachell Calhoun': {
+ photo: 'https://pycon-assets.s3.amazonaws.com/2026/media/images/rachell_calhoun.original.jpg',
+ bio: 'Co-founder of Djangonaut Space and a Django developer. Organized Django Girls workshops across multiple countries and continents for over 10 years.',
+ },
+ 'Pablo Galindo Salgado': {
+ photo: 'https://pycon-assets.s3.amazonaws.com/2026/media/images/Pablo_Galindo_Salgado.original.jpg',
+ bio: 'CPython core developer and Theoretical Physicist. Currently serving on the Python Steering Council in his 6th term and release manager for Python 3.10 and 3.11.',
+ },
+ };
+
constructor(
private dataProvider: ConferenceData,
private userProvider: UserData,
@@ -36,6 +61,18 @@ export class SessionDetailPage {
)
this.session = foundSession;
this.isOpenSpace = this.session?.tracks?.includes('open-space');
+ this.isKeynote = this.session?.tracks?.includes('keynote') || this.session?.track === 'Keynote';
+
+ // Enrich keynote sessions with speaker photo/bio
+ if (this.isKeynote) {
+ const sessionName = this.session?.name || '';
+ for (const [name, data] of Object.entries(this.keynoteSpeakers)) {
+ if (sessionName.toLowerCase().includes(name.toLowerCase())) {
+ this.keynoteData = { name, ...data };
+ break;
+ }
+ }
+ }
this.isFavorite = this.userProvider.hasFavorite(
String(this.session.id)
diff --git a/src/app/pages/session-types/session-types.page.html b/src/app/pages/session-types/session-types.page.html
index 994094e7..650022d2 100644
--- a/src/app/pages/session-types/session-types.page.html
+++ b/src/app/pages/session-types/session-types.page.html
@@ -1,14 +1,14 @@
-
+
1
- Session Types
+ Session Types
-
+
diff --git a/src/app/pages/session-types/session-types.page.scss b/src/app/pages/session-types/session-types.page.scss
index 05dd133b..3666c9f8 100644
--- a/src/app/pages/session-types/session-types.page.scss
+++ b/src/app/pages/session-types/session-types.page.scss
@@ -1,5 +1,29 @@
+ion-header {
+ background: linear-gradient(180deg, #3B3EA9 0%, #3B3EA9 100%);
+ &::after { display: none; }
+}
+
+ion-toolbar {
+ --background: transparent;
+ --border-color: transparent;
+ --color: #ffffff;
+}
+
+ion-toolbar ion-menu-button {
+ --color: #ffffff;
+}
+
+ion-title {
+ opacity: 0;
+ transition: opacity 0.25s ease;
+
+ &.title-visible {
+ opacity: 1;
+ }
+}
+
.types-hero {
- padding: 48px 24px 32px;
+ padding: 16px 24px 32px;
background: linear-gradient(180deg, #3B3EA9 23.5%, #101136 53.29%);
color: #fff;
text-align: center;
diff --git a/src/app/pages/session-types/session-types.page.ts b/src/app/pages/session-types/session-types.page.ts
index da205de6..b4b9c1f0 100644
--- a/src/app/pages/session-types/session-types.page.ts
+++ b/src/app/pages/session-types/session-types.page.ts
@@ -1,4 +1,5 @@
-import { Component } from '@angular/core';
+import { Component, ViewChild } from '@angular/core';
+import { IonContent } from '@ionic/angular';
import { LiveUpdateService } from '../../providers/live-update.service';
@Component({
@@ -7,7 +8,14 @@ import { LiveUpdateService } from '../../providers/live-update.service';
styleUrls: ['./session-types.page.scss'],
})
export class SessionTypesPage {
+ @ViewChild(IonContent) content: IonContent;
+ showTitle = false;
+
constructor(
public liveUpdateService: LiveUpdateService,
) {}
+
+ onScroll(event: any) {
+ this.showTitle = event.detail.scrollTop > 100;
+ }
}
diff --git a/src/app/pages/social-media/social-media.page.html b/src/app/pages/social-media/social-media.page.html
index 979c500e..d82c1c7a 100644
--- a/src/app/pages/social-media/social-media.page.html
+++ b/src/app/pages/social-media/social-media.page.html
@@ -1,14 +1,20 @@
-
+
1
- Social Media
+ Social Media
-
+
+
+
+
Social Media
+
Connect with the Python community online
+
+
diff --git a/src/app/pages/social-media/social-media.page.scss b/src/app/pages/social-media/social-media.page.scss
index f767e181..b9dd72c1 100644
--- a/src/app/pages/social-media/social-media.page.scss
+++ b/src/app/pages/social-media/social-media.page.scss
@@ -1,3 +1,55 @@
+ion-header {
+ background: linear-gradient(180deg, #3B3EA9 0%, #3B3EA9 100%);
+ &::after { display: none; }
+}
+
+ion-toolbar {
+ --background: transparent;
+ --border-color: transparent;
+ --color: #ffffff;
+}
+
+ion-toolbar ion-menu-button {
+ --color: #ffffff;
+}
+
+ion-title {
+ opacity: 0;
+ transition: opacity 0.25s ease;
+
+ &.title-visible {
+ opacity: 1;
+ }
+}
+
+.page-hero {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ padding: 16px 24px 32px;
+ background: linear-gradient(180deg, #3B3EA9 23.5%, #101136 53.29%);
+ color: #fff;
+ text-align: center;
+
+ .page-hero-icon {
+ font-size: 40px;
+ color: #25C8EB;
+ margin-bottom: 10px;
+ }
+
+ h1 {
+ margin: 0;
+ font-size: 1.6rem;
+ font-weight: 700;
+ }
+
+ p {
+ margin: 6px 0 0;
+ font-size: 0.9rem;
+ opacity: 0.8;
+ }
+}
+
.hashtag-banner {
display: flex;
justify-content: center;
diff --git a/src/app/pages/social-media/social-media.page.ts b/src/app/pages/social-media/social-media.page.ts
index 90b21e55..4b16c37d 100644
--- a/src/app/pages/social-media/social-media.page.ts
+++ b/src/app/pages/social-media/social-media.page.ts
@@ -1,4 +1,5 @@
-import { Component } from '@angular/core';
+import { Component, ViewChild } from '@angular/core';
+import { IonContent } from '@ionic/angular';
import { LiveUpdateService } from '../../providers/live-update.service';
@Component({
@@ -7,10 +8,17 @@ import { LiveUpdateService } from '../../providers/live-update.service';
styleUrls: ['./social-media.page.scss'],
})
export class SocialMediaPage {
+ @ViewChild(IonContent) content: IonContent;
+ showTitle = false;
+
constructor(
public liveUpdateService: LiveUpdateService,
) {}
+ onScroll(event: any) {
+ this.showTitle = event.detail.scrollTop > 100;
+ }
+
openUrl(url: string) {
window.open(url, '_system', 'location=yes');
}
diff --git a/src/app/pages/speaker-detail/speaker-detail.html b/src/app/pages/speaker-detail/speaker-detail.html
index 651feb9d..1e9b20dc 100644
--- a/src/app/pages/speaker-detail/speaker-detail.html
+++ b/src/app/pages/speaker-detail/speaker-detail.html
@@ -21,20 +21,17 @@ {{speaker?.name}}
Presentations
-
-
-
-
-
-
- {{session.name}}
- {{session.track | trackName}}
- {{session.day}} {{session.timeStart}} in {{session.location}}
-
-
-
-
-
-
+
+
+
+ {{session.name}}
+
+ {{session.track | trackName}}
+ {{session.day}} {{session.timeStart}} in {{session.location}}
+
+
+
+
diff --git a/src/app/pages/speaker-list/speaker-list.html b/src/app/pages/speaker-list/speaker-list.html
index bef28d0d..d40ff626 100644
--- a/src/app/pages/speaker-list/speaker-list.html
+++ b/src/app/pages/speaker-list/speaker-list.html
@@ -1,63 +1,40 @@
-
+
-
-
+
+
1
- Speakers
-
-
-
-
-
-
+ Speakers
-
-
-
- Speakers
-
-
-
-
-
-
-
+
+
+
+
Speakers
+
PyCon US 2026 presenters
+
-
-
-
-
-
-
-
-
-
-
- {{speaker.name}}
-
-
-
-
+
+
+
-
-
-
-
- {{session.name}}
- {{session.track | trackName}}
- {{session.day}} {{session.timeStart}} in {{session.location}}
-
-
+
+
+
+
+
+
+ {{speaker.name}}
+ 0">
+ {{speaker.sessions[0].track | trackName}}
+ {{speaker.sessions[0].name}}
+
+
+
+
-
-
-
-
-
-
diff --git a/src/app/pages/speaker-list/speaker-list.scss b/src/app/pages/speaker-list/speaker-list.scss
index ad31b524..8a2d9f48 100644
--- a/src/app/pages/speaker-list/speaker-list.scss
+++ b/src/app/pages/speaker-list/speaker-list.scss
@@ -1,48 +1,83 @@
-.speaker-card {
- display: flex;
- flex-direction: column;
- // add a border around the card to make it stand out
- border: 1px solid var(--ion-color-step-150, #d7d8da);
+ion-header {
+ background: linear-gradient(180deg, #3B3EA9 0%, #3B3EA9 100%);
+ &::after { display: none; }
}
-/* Due to the fact the cards are inside of columns the margins don't overlap
- * properly so we want to remove the extra margin between cards
- */
-ion-col:not(:last-of-type) .speaker-card {
- margin-bottom: 0;
+ion-toolbar {
+ --background: transparent;
+ --border-color: transparent;
+ --color: #ffffff;
}
-.speaker-card .speaker-item {
- --min-height: 85px;
+ion-toolbar ion-menu-button {
+ --color: #ffffff;
}
-.speaker-card .speaker-item h2 {
- font-size: 18px;
- font-weight: 500;
- letter-spacing: 0.02em;
-}
+ion-title {
+ opacity: 0;
+ transition: opacity 0.25s ease;
-.speaker-card .speaker-item p {
- font-size: 13px;
- letter-spacing: 0.02em;
+ &.title-visible {
+ opacity: 1;
+ }
}
-.speaker-card ion-card-header {
- padding: 0;
-}
+.page-hero {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ padding: 16px 24px 32px;
+ background: linear-gradient(180deg, #3B3EA9 23.5%, #101136 53.29%);
+ color: #fff;
+ text-align: center;
+
+ .page-hero-icon {
+ font-size: 40px;
+ color: #25C8EB;
+ margin-bottom: 10px;
+ }
-.speaker-card ion-card-content {
- flex: 1 1 auto;
+ h1 {
+ margin: 0;
+ font-size: 1.6rem;
+ font-weight: 700;
+ }
- padding: 0;
+ p {
+ margin: 6px 0 0;
+ font-size: 0.9rem;
+ opacity: 0.8;
+ }
}
-.ios ion-list {
- margin-bottom: 10px;
+.search-toolbar {
+ --background: var(--ion-background-color, #fff);
+ --border-color: transparent;
+ margin-top: 8px;
}
-.md ion-list {
- border-top: 1px solid var(--ion-color-step-150, #d7d8da);
+.speaker-list {
+ ion-avatar {
+ width: 44px;
+ height: 44px;
+ }
+
+ h2 {
+ font-size: 0.95rem;
+ font-weight: 600;
+ }
+
+ p {
+ font-size: 0.8rem;
+ display: flex;
+ align-items: center;
+ gap: 6px;
+ flex-wrap: wrap;
+ margin-top: 2px;
+ }
- padding: 0;
+ .track-badge {
+ font-size: 0.6rem;
+ padding: 1px 6px;
+ }
}
diff --git a/src/app/pages/speaker-list/speaker-list.ts b/src/app/pages/speaker-list/speaker-list.ts
index 6eee53e7..705679cc 100644
--- a/src/app/pages/speaker-list/speaker-list.ts
+++ b/src/app/pages/speaker-list/speaker-list.ts
@@ -16,6 +16,7 @@ export class SpeakerListPage implements OnInit {
speakerQueryText = '';
ios: boolean;
showSearchbar: boolean;
+ showTitle = false;
page: number = 0;
scrolling: boolean = false;
@@ -27,6 +28,10 @@ export class SpeakerListPage implements OnInit {
public liveUpdateService: LiveUpdateService,
) {}
+ onScroll(event: any) {
+ this.showTitle = event.detail.scrollTop > 100;
+ }
+
updateSpeakers() {
this.confData.getSpeakers("").subscribe((speakers: any[]) => {
this.speakers = speakers;
diff --git a/src/app/pages/sponsors/sponsors.page.html b/src/app/pages/sponsors/sponsors.page.html
index bbe6a09b..c8546d66 100644
--- a/src/app/pages/sponsors/sponsors.page.html
+++ b/src/app/pages/sponsors/sponsors.page.html
@@ -3,11 +3,11 @@
- Sponsors
+ Sponsors
-
+