update demo-react-switch-tabs,
This commit is contained in:
@@ -17,7 +17,7 @@ import { chevronBackOutline, refreshOutline } from 'ionicons/icons';
|
||||
|
||||
import './Tab1.css';
|
||||
|
||||
const Tab1 = () => {
|
||||
const Tab1 = (): React.JSX.Element => {
|
||||
const router = useIonRouter();
|
||||
|
||||
function handleBackClick() {
|
@@ -0,0 +1,25 @@
|
||||
import { IonContent, IonHeader, IonPage, IonTitle, IonToolbar } from '@ionic/react';
|
||||
import ExploreContainer from '../components/ExploreContainer';
|
||||
import './Tab2.css';
|
||||
|
||||
const Tab2 = (): React.JSX.Element => {
|
||||
return (
|
||||
<IonPage>
|
||||
<IonHeader>
|
||||
<IonToolbar>
|
||||
<IonTitle>Profile</IonTitle>
|
||||
</IonToolbar>
|
||||
</IonHeader>
|
||||
<IonContent fullscreen>
|
||||
<IonHeader collapse="condense">
|
||||
<IonToolbar>
|
||||
<IonTitle size="large">Profile</IonTitle>
|
||||
</IonToolbar>
|
||||
</IonHeader>
|
||||
<ExploreContainer name="Profile page" />
|
||||
</IonContent>
|
||||
</IonPage>
|
||||
);
|
||||
};
|
||||
|
||||
export default Tab2;
|
@@ -0,0 +1,25 @@
|
||||
import { IonContent, IonHeader, IonPage, IonTitle, IonToolbar } from '@ionic/react';
|
||||
import ExploreContainer from '../components/ExploreContainer';
|
||||
import './Tab3.css';
|
||||
|
||||
const Tab3 = (): React.JSX.Element => {
|
||||
return (
|
||||
<IonPage>
|
||||
<IonHeader>
|
||||
<IonToolbar>
|
||||
<IonTitle>Settings</IonTitle>
|
||||
</IonToolbar>
|
||||
</IonHeader>
|
||||
<IonContent fullscreen>
|
||||
<IonHeader collapse="condense">
|
||||
<IonToolbar>
|
||||
<IonTitle size="large">Settings</IonTitle>
|
||||
</IonToolbar>
|
||||
</IonHeader>
|
||||
<ExploreContainer name="Settings page" />
|
||||
</IonContent>
|
||||
</IonPage>
|
||||
);
|
||||
};
|
||||
|
||||
export default Tab3;
|
@@ -0,0 +1,24 @@
|
||||
.container {
|
||||
text-align: center;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
right: 0;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
}
|
||||
|
||||
.container strong {
|
||||
font-size: 20px;
|
||||
line-height: 26px;
|
||||
}
|
||||
|
||||
.container p {
|
||||
font-size: 16px;
|
||||
line-height: 22px;
|
||||
color: #8c8c8c;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.container a {
|
||||
text-decoration: none;
|
||||
}
|
@@ -0,0 +1,15 @@
|
||||
import './ExploreContainer.css';
|
||||
|
||||
interface ExploreContainerProps {
|
||||
name: string;
|
||||
}
|
||||
|
||||
const ExploreContainer = ({ name }: ExploreContainerProps): React.JSX.Element => {
|
||||
return (
|
||||
<div className="container">
|
||||
<strong>{name}</strong>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default ExploreContainer;
|
@@ -16,9 +16,24 @@ import { useRef } from 'react';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { Redirect, Route } from 'react-router';
|
||||
|
||||
const SwitchTabBar = () => {
|
||||
interface TabItem {
|
||||
label: string;
|
||||
url: string;
|
||||
icon: string;
|
||||
color: string;
|
||||
backgroundColor: string;
|
||||
component: React.ComponentType;
|
||||
}
|
||||
|
||||
interface AnimationConfig {
|
||||
property: string;
|
||||
fromValue: string;
|
||||
toValue: string;
|
||||
}
|
||||
|
||||
const SwitchTabBar = (): React.JSX.Element => {
|
||||
const [activeTab, setActiveTab] = useState('tab0');
|
||||
const switchRefs = useRef([]);
|
||||
const switchRefs = useRef<(CreateAnimation | null)[]>([]);
|
||||
|
||||
const tabs = [
|
||||
{
|
||||
@@ -61,8 +76,8 @@ const SwitchTabBar = () => {
|
||||
easing: 'ease-in-out',
|
||||
};
|
||||
|
||||
const getTabButtonStyle = (tab) => {
|
||||
const tabStyle = {
|
||||
const getTabButtonStyle = (tab: TabItem): React.CSSProperties => {
|
||||
const tabStyle: React.CSSProperties = {
|
||||
backgroundColor: tab.backgroundColor,
|
||||
color: tab.color,
|
||||
transition: '0.5s all ease-in-out',
|
@@ -0,0 +1,121 @@
|
||||
import { CreateAnimation, IonIcon, IonLabel, IonRouterOutlet, IonTabBar, IonTabButton, IonTabs } from "@ionic/react";
|
||||
import { IonReactRouter } from "@ionic/react-router";
|
||||
import { home, person, settings } from 'ionicons/icons';
|
||||
import Tab1 from '../pages/Tab1';
|
||||
import Tab2 from '../pages/Tab2';
|
||||
import Tab3 from '../pages/Tab3';
|
||||
import { useRef } from "react";
|
||||
import { useEffect, useState } from "react";
|
||||
import { Redirect, Route } from "react-router";
|
||||
|
||||
const SwitchTabBar = () => {
|
||||
|
||||
const [activeTab, setActiveTab] = useState("tab0");
|
||||
const switchRefs = useRef([]);
|
||||
|
||||
const tabs = [
|
||||
|
||||
{
|
||||
label: "Home",
|
||||
url: "/home",
|
||||
icon: home,
|
||||
color: "#76b140",
|
||||
backgroundColor: "#ddf7c5",
|
||||
component: Tab1
|
||||
},
|
||||
{
|
||||
label: "Profile",
|
||||
url: "/profile",
|
||||
icon: person,
|
||||
color: "#e46062",
|
||||
backgroundColor: "#fcddde",
|
||||
component: Tab2
|
||||
},
|
||||
{
|
||||
label: "Settings",
|
||||
url: "/settings",
|
||||
icon: settings,
|
||||
color: "#3578e5",
|
||||
backgroundColor: "#e7f0ff",
|
||||
component: Tab3
|
||||
}
|
||||
];
|
||||
|
||||
const revealAnimation = {
|
||||
|
||||
property: "transform",
|
||||
fromValue: "translateX(-30px)",
|
||||
toValue: "translateX(0px)"
|
||||
};
|
||||
|
||||
const switchAnimation = {
|
||||
|
||||
duration: 200,
|
||||
direction: "normal",
|
||||
iterations: "1",
|
||||
fromTo: [revealAnimation],
|
||||
easing: "ease-in-out"
|
||||
};
|
||||
|
||||
const getTabButtonStyle = tab => {
|
||||
|
||||
const tabStyle = {
|
||||
|
||||
backgroundColor: tab.backgroundColor,
|
||||
color: tab.color,
|
||||
transition: "0.5s all ease-in-out"
|
||||
};
|
||||
|
||||
return tabStyle;
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
const tabIndex = activeTab.match(/\d+/)[0];
|
||||
switchRefs.current[tabIndex].animation.play();
|
||||
}, [activeTab]);
|
||||
|
||||
return (
|
||||
|
||||
<IonReactRouter>
|
||||
<IonTabs>
|
||||
<IonRouterOutlet>
|
||||
|
||||
{tabs.map((tab, index) => {
|
||||
|
||||
return (
|
||||
<Route key={index} exact path={tab.url}>
|
||||
<tab.component />
|
||||
</Route>
|
||||
);
|
||||
})}
|
||||
|
||||
<Route exact path="/">
|
||||
<Redirect to="/home" />
|
||||
</Route>
|
||||
</IonRouterOutlet>
|
||||
<IonTabBar slot="bottom" onIonTabsDidChange={e => setActiveTab(e.detail.tab)}>
|
||||
|
||||
{tabs.map((tab, index) => {
|
||||
|
||||
const tabStyle = getTabButtonStyle(tab);
|
||||
const isActive = activeTab === `tab${index}`;
|
||||
|
||||
return (
|
||||
<IonTabButton key={index} style={isActive ? tabStyle : {}} tab={`tab${index}`} href={tab.url}>
|
||||
|
||||
<IonIcon icon={tab.icon} />
|
||||
|
||||
{isActive && <CreateAnimation ref={ref => switchRefs.current[index] = ref} {...switchAnimation}>
|
||||
<IonLabel>{tab.label}</IonLabel>
|
||||
</CreateAnimation>}
|
||||
</IonTabButton>
|
||||
);
|
||||
})}
|
||||
</IonTabBar>
|
||||
</IonTabs>
|
||||
</IonReactRouter>
|
||||
);
|
||||
}
|
||||
|
||||
export default SwitchTabBar;
|
@@ -0,0 +1,25 @@
|
||||
import { IonContent, IonHeader, IonPage, IonTitle, IonToolbar } from '@ionic/react';
|
||||
import ExploreContainer from '../components/ExploreContainer';
|
||||
import './Tab1.css';
|
||||
|
||||
const Tab1 = () => {
|
||||
return (
|
||||
<IonPage>
|
||||
<IonHeader>
|
||||
<IonToolbar>
|
||||
<IonTitle>Home</IonTitle>
|
||||
</IonToolbar>
|
||||
</IonHeader>
|
||||
<IonContent fullscreen>
|
||||
<IonHeader collapse="condense">
|
||||
<IonToolbar>
|
||||
<IonTitle size="large">Home</IonTitle>
|
||||
</IonToolbar>
|
||||
</IonHeader>
|
||||
<ExploreContainer name="Home page" />
|
||||
</IonContent>
|
||||
</IonPage>
|
||||
);
|
||||
};
|
||||
|
||||
export default Tab1;
|
@@ -0,0 +1,99 @@
|
||||
/* Ionic Variables and Theming. For more info, please see:
|
||||
http://ionicframework.com/docs/theming/ */
|
||||
|
||||
/** Ionic CSS Variables **/
|
||||
:root {
|
||||
/** primary **/
|
||||
--ion-color-primary: #3880ff;
|
||||
--ion-color-primary-rgb: 56, 128, 255;
|
||||
--ion-color-primary-contrast: #ffffff;
|
||||
--ion-color-primary-contrast-rgb: 255, 255, 255;
|
||||
--ion-color-primary-shade: #3171e0;
|
||||
--ion-color-primary-tint: #4c8dff;
|
||||
|
||||
/** secondary **/
|
||||
--ion-color-secondary: #3dc2ff;
|
||||
--ion-color-secondary-rgb: 61, 194, 255;
|
||||
--ion-color-secondary-contrast: #ffffff;
|
||||
--ion-color-secondary-contrast-rgb: 255, 255, 255;
|
||||
--ion-color-secondary-shade: #36abe0;
|
||||
--ion-color-secondary-tint: #50c8ff;
|
||||
|
||||
/** tertiary **/
|
||||
--ion-color-tertiary: #5260ff;
|
||||
--ion-color-tertiary-rgb: 82, 96, 255;
|
||||
--ion-color-tertiary-contrast: #ffffff;
|
||||
--ion-color-tertiary-contrast-rgb: 255, 255, 255;
|
||||
--ion-color-tertiary-shade: #4854e0;
|
||||
--ion-color-tertiary-tint: #6370ff;
|
||||
|
||||
/** success **/
|
||||
--ion-color-success: #2dd36f;
|
||||
--ion-color-success-rgb: 45, 211, 111;
|
||||
--ion-color-success-contrast: #ffffff;
|
||||
--ion-color-success-contrast-rgb: 255, 255, 255;
|
||||
--ion-color-success-shade: #28ba62;
|
||||
--ion-color-success-tint: #42d77d;
|
||||
|
||||
/** warning **/
|
||||
--ion-color-warning: #ffc409;
|
||||
--ion-color-warning-rgb: 255, 196, 9;
|
||||
--ion-color-warning-contrast: #000000;
|
||||
--ion-color-warning-contrast-rgb: 0, 0, 0;
|
||||
--ion-color-warning-shade: #e0ac08;
|
||||
--ion-color-warning-tint: #ffca22;
|
||||
|
||||
/** danger **/
|
||||
--ion-color-danger: #eb445a;
|
||||
--ion-color-danger-rgb: 235, 68, 90;
|
||||
--ion-color-danger-contrast: #ffffff;
|
||||
--ion-color-danger-contrast-rgb: 255, 255, 255;
|
||||
--ion-color-danger-shade: #cf3c4f;
|
||||
--ion-color-danger-tint: #ed576b;
|
||||
|
||||
/** dark **/
|
||||
--ion-color-dark: #222428;
|
||||
--ion-color-dark-rgb: 34, 36, 40;
|
||||
--ion-color-dark-contrast: #ffffff;
|
||||
--ion-color-dark-contrast-rgb: 255, 255, 255;
|
||||
--ion-color-dark-shade: #1e2023;
|
||||
--ion-color-dark-tint: #383a3e;
|
||||
|
||||
/** medium **/
|
||||
--ion-color-medium: #92949c;
|
||||
--ion-color-medium-rgb: 146, 148, 156;
|
||||
--ion-color-medium-contrast: #ffffff;
|
||||
--ion-color-medium-contrast-rgb: 255, 255, 255;
|
||||
--ion-color-medium-shade: #808289;
|
||||
--ion-color-medium-tint: #9d9fa6;
|
||||
|
||||
/** light **/
|
||||
--ion-color-light: #f4f5f8;
|
||||
--ion-color-light-rgb: 244, 245, 248;
|
||||
--ion-color-light-contrast: #000000;
|
||||
--ion-color-light-contrast-rgb: 0, 0, 0;
|
||||
--ion-color-light-shade: #d7d8da;
|
||||
--ion-color-light-tint: #f5f6f9;
|
||||
}
|
||||
|
||||
ion-tab-bar {
|
||||
|
||||
padding: 1rem;
|
||||
}
|
||||
|
||||
ion-tab-button {
|
||||
|
||||
flex-direction: row;
|
||||
border-radius: 20px;
|
||||
}
|
||||
|
||||
ion-tab-button ion-icon {
|
||||
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
|
||||
ion-tab-button ion-label {
|
||||
|
||||
margin-left: 1rem;
|
||||
font-size: 0.8rem;
|
||||
}
|
Reference in New Issue
Block a user