diff --git a/03_source/mobile/src/pages/DemoReactSwitchTabs/AppPages/Tab1.jsx b/03_source/mobile/src/pages/DemoReactSwitchTabs/AppPages/Tab1.tsx
similarity index 96%
rename from 03_source/mobile/src/pages/DemoReactSwitchTabs/AppPages/Tab1.jsx
rename to 03_source/mobile/src/pages/DemoReactSwitchTabs/AppPages/Tab1.tsx
index 24873ba..d14c4a9 100644
--- a/03_source/mobile/src/pages/DemoReactSwitchTabs/AppPages/Tab1.jsx
+++ b/03_source/mobile/src/pages/DemoReactSwitchTabs/AppPages/Tab1.tsx
@@ -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() {
diff --git a/03_source/mobile/src/pages/DemoReactSwitchTabs/AppPages/Tab2.tsx b/03_source/mobile/src/pages/DemoReactSwitchTabs/AppPages/Tab2.tsx
new file mode 100644
index 0000000..f69a263
--- /dev/null
+++ b/03_source/mobile/src/pages/DemoReactSwitchTabs/AppPages/Tab2.tsx
@@ -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 (
+
+
+
+ Profile
+
+
+
+
+
+ Profile
+
+
+
+
+
+ );
+};
+
+export default Tab2;
diff --git a/03_source/mobile/src/pages/DemoReactSwitchTabs/AppPages/Tab3.tsx b/03_source/mobile/src/pages/DemoReactSwitchTabs/AppPages/Tab3.tsx
new file mode 100644
index 0000000..48d6189
--- /dev/null
+++ b/03_source/mobile/src/pages/DemoReactSwitchTabs/AppPages/Tab3.tsx
@@ -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 (
+
+
+
+ Settings
+
+
+
+
+
+ Settings
+
+
+
+
+
+ );
+};
+
+export default Tab3;
diff --git a/03_source/mobile/src/pages/DemoReactSwitchTabs/TestComponents/ExploreContainer.css b/03_source/mobile/src/pages/DemoReactSwitchTabs/TestComponents/ExploreContainer.css
new file mode 100644
index 0000000..e99f514
--- /dev/null
+++ b/03_source/mobile/src/pages/DemoReactSwitchTabs/TestComponents/ExploreContainer.css
@@ -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;
+}
\ No newline at end of file
diff --git a/03_source/mobile/src/pages/DemoReactSwitchTabs/TestComponents/ExploreContainer.tsx b/03_source/mobile/src/pages/DemoReactSwitchTabs/TestComponents/ExploreContainer.tsx
new file mode 100644
index 0000000..202447c
--- /dev/null
+++ b/03_source/mobile/src/pages/DemoReactSwitchTabs/TestComponents/ExploreContainer.tsx
@@ -0,0 +1,15 @@
+import './ExploreContainer.css';
+
+interface ExploreContainerProps {
+ name: string;
+}
+
+const ExploreContainer = ({ name }: ExploreContainerProps): React.JSX.Element => {
+ return (
+
+ {name}
+
+ );
+};
+
+export default ExploreContainer;
diff --git a/03_source/mobile/src/pages/DemoReactSwitchTabs/components/SwitchTabBar.jsx b/03_source/mobile/src/pages/DemoReactSwitchTabs/TestComponents/SwitchTabBar.tsx
similarity index 86%
rename from 03_source/mobile/src/pages/DemoReactSwitchTabs/components/SwitchTabBar.jsx
rename to 03_source/mobile/src/pages/DemoReactSwitchTabs/TestComponents/SwitchTabBar.tsx
index 6ec16cf..08fdc46 100644
--- a/03_source/mobile/src/pages/DemoReactSwitchTabs/components/SwitchTabBar.jsx
+++ b/03_source/mobile/src/pages/DemoReactSwitchTabs/TestComponents/SwitchTabBar.tsx
@@ -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',
diff --git a/03_source/mobile/src/pages/DemoReactSwitchTabs/components/ExploreContainer.jsx b/03_source/mobile/src/pages/DemoReactSwitchTabs/components/ExploreContainer.tsx
similarity index 100%
rename from 03_source/mobile/src/pages/DemoReactSwitchTabs/components/ExploreContainer.jsx
rename to 03_source/mobile/src/pages/DemoReactSwitchTabs/components/ExploreContainer.tsx
diff --git a/03_source/mobile/src/pages/DemoReactSwitchTabs/components/SwitchTabBar.tsx b/03_source/mobile/src/pages/DemoReactSwitchTabs/components/SwitchTabBar.tsx
new file mode 100644
index 0000000..7968810
--- /dev/null
+++ b/03_source/mobile/src/pages/DemoReactSwitchTabs/components/SwitchTabBar.tsx
@@ -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 (
+
+
+
+
+
+ {tabs.map((tab, index) => {
+
+ return (
+
+
+
+ );
+ })}
+
+
+
+
+
+ setActiveTab(e.detail.tab)}>
+
+ {tabs.map((tab, index) => {
+
+ const tabStyle = getTabButtonStyle(tab);
+ const isActive = activeTab === `tab${index}`;
+
+ return (
+
+
+
+
+ {isActive && switchRefs.current[index] = ref} {...switchAnimation}>
+ {tab.label}
+ }
+
+ );
+ })}
+
+
+
+ );
+}
+
+export default SwitchTabBar;
\ No newline at end of file
diff --git a/03_source/mobile/src/pages/DemoReactSwitchTabs/pages/Tab1.css b/03_source/mobile/src/pages/DemoReactSwitchTabs/pages/Tab1.css
new file mode 100644
index 0000000..e69de29
diff --git a/03_source/mobile/src/pages/DemoReactSwitchTabs/pages/Tab1.tsx b/03_source/mobile/src/pages/DemoReactSwitchTabs/pages/Tab1.tsx
new file mode 100644
index 0000000..20895c3
--- /dev/null
+++ b/03_source/mobile/src/pages/DemoReactSwitchTabs/pages/Tab1.tsx
@@ -0,0 +1,25 @@
+import { IonContent, IonHeader, IonPage, IonTitle, IonToolbar } from '@ionic/react';
+import ExploreContainer from '../components/ExploreContainer';
+import './Tab1.css';
+
+const Tab1 = () => {
+ return (
+
+
+
+ Home
+
+
+
+
+
+ Home
+
+
+
+
+
+ );
+};
+
+export default Tab1;
diff --git a/03_source/mobile/src/pages/DemoReactSwitchTabs/pages/Tab2.css b/03_source/mobile/src/pages/DemoReactSwitchTabs/pages/Tab2.css
new file mode 100644
index 0000000..e69de29
diff --git a/03_source/mobile/src/pages/DemoReactSwitchTabs/AppPages/Tab2.jsx b/03_source/mobile/src/pages/DemoReactSwitchTabs/pages/Tab2.tsx
similarity index 100%
rename from 03_source/mobile/src/pages/DemoReactSwitchTabs/AppPages/Tab2.jsx
rename to 03_source/mobile/src/pages/DemoReactSwitchTabs/pages/Tab2.tsx
diff --git a/03_source/mobile/src/pages/DemoReactSwitchTabs/pages/Tab3.css b/03_source/mobile/src/pages/DemoReactSwitchTabs/pages/Tab3.css
new file mode 100644
index 0000000..e69de29
diff --git a/03_source/mobile/src/pages/DemoReactSwitchTabs/AppPages/Tab3.jsx b/03_source/mobile/src/pages/DemoReactSwitchTabs/pages/Tab3.tsx
similarity index 100%
rename from 03_source/mobile/src/pages/DemoReactSwitchTabs/AppPages/Tab3.jsx
rename to 03_source/mobile/src/pages/DemoReactSwitchTabs/pages/Tab3.tsx
diff --git a/03_source/mobile/src/pages/DemoReactSwitchTabs/theme/variables.css b/03_source/mobile/src/pages/DemoReactSwitchTabs/theme/variables.css
new file mode 100644
index 0000000..6e146ff
--- /dev/null
+++ b/03_source/mobile/src/pages/DemoReactSwitchTabs/theme/variables.css
@@ -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;
+}
\ No newline at end of file