Skip to content

Commit

Permalink
Merge pull request #170 from FlutterKaigi/feature/add-sponsor-detail-…
Browse files Browse the repository at this point in the history
…page

スポンサー詳細ページを追加
  • Loading branch information
tatsutakein authored Sep 24, 2023
2 parents 4c8936e + faa9705 commit 62748ad
Show file tree
Hide file tree
Showing 6 changed files with 434 additions and 2 deletions.
4 changes: 2 additions & 2 deletions lib/app/app.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import 'package:confwebsite2023/app/config.dart';
import 'package:confwebsite2023/app/home_page.dart';
import 'package:confwebsite2023/app/sponsor_page.dart';
import 'package:confwebsite2023/core/theme.dart';
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
Expand All @@ -16,7 +16,7 @@ class App extends ConsumerWidget {
theme: lightTheme, // Specified but not used
darkTheme: darkTheme,
themeMode: ThemeMode.dark,
home: const MainPage(),
home: const SponsorPage(),
localizationsDelegates: AppLocalizations.localizationsDelegates,
supportedLocales: AppLocalizations.supportedLocales,
);
Expand Down
141 changes: 141 additions & 0 deletions lib/app/sponsor_page.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
import 'dart:math';

import 'package:confwebsite2023/core/components/responsive_widget.dart';
import 'package:confwebsite2023/core/theme.dart';
import 'package:confwebsite2023/features/footer/ui/footer.dart';
import 'package:confwebsite2023/features/header/data/header_item_button_data.dart';
import 'package:confwebsite2023/features/header/ui/header_widget.dart';
import 'package:confwebsite2023/features/sponsor/ui/detail/sponsor_detail.dart';
import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:js/js_util.dart' as js_util;

final class SponsorPage extends HookWidget {
const SponsorPage({super.key});

@override
Widget build(BuildContext context) {
final scrollController = useScrollController();

const sectionKeys = (
event: GlobalObjectKey('eventSectionKey'),
session: GlobalObjectKey('sessionSectionKey'),
sponsor: GlobalObjectKey('sponsorSectionKey'),
staff: GlobalObjectKey('staffSectionKey'),
);

final items = <HeaderItemButtonData>[
HeaderItemButtonData(
title: 'Staff',
onPressed: () async => Scrollable.ensureVisible(
sectionKeys.staff.currentContext!,
curve: Curves.easeOutCirc,
duration: const Duration(milliseconds: 750),
),
),
];

return Scaffold(
backgroundColor: baselineColorScheme.ref.secondary.secondary10,
body: _MainPageBody(
scrollController: scrollController,
staffSectionKey: sectionKeys.staff,
items: items,
),
);
}
}

class _MainPageBody extends StatelessWidget {
const _MainPageBody({
required this.scrollController,
required this.staffSectionKey,
required this.items,
});

final ScrollController scrollController;
final GlobalKey<State<StatefulWidget>> staffSectionKey;
final List<HeaderItemButtonData> items;

@override
Widget build(BuildContext context) {
final width = MediaQuery.sizeOf(context).width;
final largeScreenSize = ResponsiveWidget.largeScreenSize.toDouble();
final horizontal = max<double>(16, (width - largeScreenSize) / 4.0);
final padding = EdgeInsets.symmetric(
horizontal: horizontal,
);

js_util.callMethod<void>(js_util.globalThis, '_show', []);

return Stack(
children: [
const SizedBox(
width: double.infinity,
height: 800,
child: DecoratedBox(
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
colors: [
Color(0xFF602678),
Color(0x004B0082),
],
),
),
),
),
CustomScrollView(
controller: scrollController,
slivers: [
_Sliver(
padding: padding,
child: HeaderBar(
items: items,
onTitleTap: () async => scrollController.animateTo(
0,
duration: const Duration(milliseconds: 750),
curve: Curves.easeOutCirc,
),
),
),
const SliverToBoxAdapter(
child: Spaces.vertical_30,
),
_Sliver(
padding: padding,
child: const SponsorDetail(),
),
const SliverToBoxAdapter(
child: Spaces.vertical_200,
),
const SliverToBoxAdapter(
child: Footer(),
),
],
),
],
);
}
}

class _Sliver extends StatelessWidget {
const _Sliver({
required this.child,
required this.padding,
});

final Widget child;
final EdgeInsets padding;

@override
Widget build(BuildContext context) {
return SliverPadding(
padding: padding,
sliver: SliverToBoxAdapter(
child: child,
),
);
}
}
62 changes: 62 additions & 0 deletions lib/features/sponsor/ui/detail/sponsor_detail.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import 'package:confwebsite2023/core/components/responsive_widget.dart';
import 'package:confwebsite2023/core/gen/assets.gen.dart';
import 'package:confwebsite2023/core/theme.dart';
import 'package:confwebsite2023/features/sponsor/data/sponsor.dart';
import 'package:confwebsite2023/features/sponsor/data/sponsor_plan.dart';
import 'package:confwebsite2023/features/sponsor/data/sponsor_session.dart';
import 'package:confwebsite2023/features/sponsor/ui/detail/sponsor_detail_content.dart';
import 'package:flutter/material.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';

final class SponsorDetail extends ConsumerWidget {
const SponsorDetail({super.key});

@override
Widget build(BuildContext context, WidgetRef ref) {
// TODO: データを動的に取得する
const sponsor = _sponsor;

return ResponsiveWidget(
largeWidget: SponsorDetailContent(
sponsor: sponsor,
h1TextStyle: AppTextStyle.pcHeading1,
h2TextStyle: AppTextStyle.pcHeading2,
onTweetPressed: () {},
onCopyUrlPressed: () {},
),
smallWidget: SponsorDetailContent(
sponsor: sponsor,
h1TextStyle: AppTextStyle.spHeading1,
h2TextStyle: AppTextStyle.spHeading2,
onTweetPressed: () {},
onCopyUrlPressed: () {},
),
);
}
}

// TODO: データを動的に取得する
const _sponsor = Sponsor(
name: 'flutterkaigi',
displayName: '企業名・ブランド名',
url: 'https://flutterkaigi.jp/2023/',
logoAssetName: Assets.flutterkaigiLogoShadowed,
plan: SponsorPlan.platinum,
session: SponsorSession(
id: 'id',
title: 'Flutterアプリ開発におけるモジュール分割戦略 〜dart15万行を100分割する〜',
url: 'https://flutterkaigi.jp/2023/',
scheduledAt: '2023年11月10日 11:10〜11:55(45分)',
),
introduction: '紹介文(600字程度)\n紹介文(600字程度)\n紹介文(600字程度)',
);

// const _sponsor = Sponsor(
// name: 'flutterkaigi',
// displayName: '企業名・ブランド名',
// url: 'https://flutterkaigi.jp/2023/',
// logoAssetName: Assets.flutterkaigiLogoShadowed,
// plan: SponsorPlan.platinum,
// session: null,
// introduction: '紹介文(600字程度)\n紹介文(600字程度)\n紹介文(600字程度)',
// );
94 changes: 94 additions & 0 deletions lib/features/sponsor/ui/detail/sponsor_detail_content.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
import 'package:confwebsite2023/core/components/social_share.dart';
import 'package:confwebsite2023/core/theme.dart';
import 'package:confwebsite2023/features/sponsor/data/sponsor.dart';
import 'package:confwebsite2023/features/sponsor/data/sponsor_plan.dart';
import 'package:confwebsite2023/features/sponsor/ui/detail/sponsor_introduction.dart';
import 'package:confwebsite2023/features/sponsor/ui/detail/sponsor_session.dart';
import 'package:confwebsite2023/features/sponsor/ui/sponsor_plan_header.dart';
import 'package:confwebsite2023/features/sponsor/ui/sponsors_header.dart';
import 'package:flutter/material.dart';

final class SponsorDetailContent extends StatelessWidget {
const SponsorDetailContent({
required this.sponsor,
required this.h1TextStyle,
required this.h2TextStyle,
required this.onTweetPressed,
required this.onCopyUrlPressed,
super.key,
});

final Sponsor sponsor;

final TextStyle h1TextStyle;
final TextStyle h2TextStyle;
final VoidCallback? onTweetPressed;
final VoidCallback? onCopyUrlPressed;

@override
Widget build(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SponsorsHeader(
style: h1TextStyle,
),
SizedBox(
width: double.infinity,
child: SocialShare(
onTweetPressed: onTweetPressed,
onCopyUrlPressed: onCopyUrlPressed,
),
),
Spaces.vertical_20,
Container(
width: double.infinity,
decoration: const BoxDecoration(
color: Color(0x22000000),
borderRadius: BorderRadius.all(Radius.circular(12)),
),
child: Padding(
padding: const EdgeInsets.all(40),
child: Column(
children: [
SponsorPlanHeader(
text: switch (sponsor.plan) {
SponsorPlan.platinum => 'Platinum Sponsor',
SponsorPlan.gold => 'Gold Sponsor',
SponsorPlan.silver => 'Silver Sponsor',
},
style: h2TextStyle,
plan: sponsor.plan,
),
Column(
children: [
SponsorIntroduction(
assetName: sponsor.logoAssetName,
name: sponsor.displayName,
url: sponsor.url,
introduction: sponsor.introduction,
),
Spaces.vertical_40,
if (sponsor.session != null) ...[
const Divider(height: 1),
Spaces.vertical_40,
SponsorSessionSection(session: sponsor.session!),
],
],
),
],
),
),
),
Spaces.vertical_20,
SizedBox(
width: double.infinity,
child: SocialShare(
onTweetPressed: onTweetPressed,
onCopyUrlPressed: onCopyUrlPressed,
),
),
],
);
}
}
79 changes: 79 additions & 0 deletions lib/features/sponsor/ui/detail/sponsor_introduction.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import 'package:confwebsite2023/core/theme.dart';
import 'package:flutter/material.dart';
import 'package:flutter_svg/svg.dart';
import 'package:url_launcher/link.dart';

final class SponsorIntroduction extends StatelessWidget {
const SponsorIntroduction({
required this.assetName,
required this.name,
required this.url,
required this.introduction,
super.key,
});

final String assetName;
final String name;
final String url;
final String introduction;

@override
Widget build(BuildContext context) {
final textTheme = Theme.of(context).textTheme;

return Column(
children: [
SvgPicture.asset(
assetName,
width: 400,
height: 200,
fit: BoxFit.fitHeight,
),
SizedBox(
width: double.infinity,
child: Padding(
padding: const EdgeInsets.all(40),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
name,
style: textTheme.headlineLarge,
),
Spaces.vertical_16,
Transform.translate(
offset: const Offset(-16, 0),
child: Link(
uri: Uri.parse(url),
target: LinkTarget.blank,
builder: (_, followLink) => TextButton(
style: TextButton.styleFrom(
padding: const EdgeInsets.symmetric(
horizontal: 16,
),
alignment: Alignment.centerLeft,
textStyle: Theme.of(context)
.textTheme
.bodyLarge
?.copyWith(
color: baselineColorScheme.sys.dark.onBackground,
),
),
onPressed: followLink,
child: Text(url),
),
),
),
Spaces.vertical_16,
Text(
introduction,
style: textTheme.bodyLarge,
),
],
),
),
),
],
);
}
}
Loading

0 comments on commit 62748ad

Please sign in to comment.