diff --git a/03_source/mobile/src/pages/DemoReactMarvelApp/components/CharacterItem.module.scss b/03_source/mobile/src/pages/DemoReactMarvelApp/components/CharacterItem.module.scss new file mode 100644 index 0000000..19c374f --- /dev/null +++ b/03_source/mobile/src/pages/DemoReactMarvelApp/components/CharacterItem.module.scss @@ -0,0 +1,43 @@ +.characterContainer { + + position: relative; + text-align: center; + color: white; +} + +ion-item { + --padding-start: 0; + --inner-padding-end: 0; +} + +ion-label { + margin-top: 12px; + margin-bottom: 12px; +} + +.characterNameContainer { + + display: flex; + flex-direction: row; + justify-content: space-between; + align-items: center; + align-content: center; + position: absolute; + z-index: 99999; + background-color: rgba(0, 0, 0, 0.7); + bottom: 0; + width: 100%; + padding-left: 1rem; + padding-right: 1rem; +} + +.characterNameContainer ion-icon { + + margin-top: 0.1rem; +} + +.characterNameContainer ion-label { + + font-size: 1rem; + font-weight: 500; +} \ No newline at end of file diff --git a/03_source/mobile/src/pages/DemoReactMarvelApp/components/CharacterItem.tsx b/03_source/mobile/src/pages/DemoReactMarvelApp/components/CharacterItem.tsx new file mode 100644 index 0000000..e884132 --- /dev/null +++ b/03_source/mobile/src/pages/DemoReactMarvelApp/components/CharacterItem.tsx @@ -0,0 +1,50 @@ +import { IonCol, IonIcon, IonImg, IonItem, IonLabel, IonSkeletonText } from "@ionic/react"; +import { chevronForwardOutline } from "ionicons/icons"; +import { Character } from "../../types"; +import styles from "./CharacterItem.module.scss"; + +interface Props { + details: Character; + load?: boolean; + grid?: boolean; +} + +const CharacterItem = (props: Props): React.JSX.Element => { + + const { details, load = false, grid = true } = props; + const loadAmount = 20; + + if (!load) { + return ( + + + + +
+ { details.name } + +
+
+
+ ); + } else { + + return ( + + <> + { Array.from({length: loadAmount }, (item, index) => { + + return ( + + + + + + ); + })} + + ); + } +} + +export default CharacterItem; diff --git a/03_source/mobile/src/pages/DemoReactMarvelApp/index.tsx b/03_source/mobile/src/pages/DemoReactMarvelApp/index.tsx index 6f20bff..30aff92 100644 --- a/03_source/mobile/src/pages/DemoReactMarvelApp/index.tsx +++ b/03_source/mobile/src/pages/DemoReactMarvelApp/index.tsx @@ -1,38 +1,31 @@ -import { IonIcon, IonLabel, IonRouterOutlet, IonTabBar, IonTabButton, IonTabs } from '@ionic/react'; +import { IonRouterOutlet, IonTabs } from '@ionic/react'; -import { cloudOutline, searchOutline } from 'ionicons/icons'; import { Route, Redirect } from 'react-router'; -import Tab1 from './AppPages/Tab1'; -import Tab2 from './AppPages/Tab2'; +// import Tab1 from './AppPages/Tab1'; +// import Tab2 from './AppPages/Tab2'; -import './style.scss'; +import './theme/variables.scss'; +import Home from './pages/Home'; +import ViewCharacter from './pages/ViewCharacter'; +import Info from './pages/Info'; function DemoReactMarvelApp() { return ( - - + + - - + + + + + - + - - {/* */} - - - - Dashboard - - - - Search - - ); } diff --git a/03_source/mobile/src/pages/DemoReactMarvelApp/pages/Home.css b/03_source/mobile/src/pages/DemoReactMarvelApp/pages/Home.css new file mode 100644 index 0000000..5d95270 --- /dev/null +++ b/03_source/mobile/src/pages/DemoReactMarvelApp/pages/Home.css @@ -0,0 +1,32 @@ +.character-container { + + position: relative; + text-align: center; + color: white; +} +.character-name-container { + + display: flex; + flex-direction: row; + justify-content: space-between; + align-items: center; + align-content: center; + position:absolute; + z-index: 99999; + background-color: rgba(0,0,0,0.7); + bottom: 0; + width: 100%; + padding-left: 1rem; + padding-right: 1rem; +} + +.character-name-container ion-icon { + + margin-top: 0.5rem; +} + +.character-name-container ion-label { + + font-size: 1rem; + font-weight: 500; +} \ No newline at end of file diff --git a/03_source/mobile/src/pages/DemoReactMarvelApp/pages/Home.tsx b/03_source/mobile/src/pages/DemoReactMarvelApp/pages/Home.tsx new file mode 100644 index 0000000..722f593 --- /dev/null +++ b/03_source/mobile/src/pages/DemoReactMarvelApp/pages/Home.tsx @@ -0,0 +1,208 @@ +import { useEffect, useState } from 'react'; +import { + IonButton, + IonButtons, + IonContent, + IonHeader, + IonIcon, + IonInfiniteScroll, + IonInfiniteScrollContent, + IonPage, + IonRow, + IonTitle, + IonToast, + IonToolbar, + useIonRouter, +} from '@ionic/react'; + +import './Home.css'; +import { + addOutline, + chevronBackOutline, + expandOutline, + gridOutline, + informationCircleOutline, + searchOutline, +} from 'ionicons/icons'; +import CharacterItem from '../components/CharacterItem'; + +const Home = (): React.JSX.Element => { + const [grid, setGrid] = useState(true); + const [characters, setCharacters] = useState([]); + const [amountLoaded, setAmountLoaded] = useState(20); + const [showToast, setShowToast] = useState<{ show: boolean; message: string }>({ + show: false, + message: '', + }); + + useEffect(() => { + const buttInstall = document.getElementById('buttInstall'); + window.addEventListener('beforeinstallprompt', (event) => { + console.log('šŸ‘', 'beforeinstallprompt', event); + + // Save the event so it can be triggered later. + window.deferredPrompt = event; + buttInstall.classList.toggle('hidden', false); + }); + + window.addEventListener('appinstalled', (event) => { + console.log('šŸ‘', 'appinstalled', event); + // Clear the deferredPrompt so it can be garbage collected + window.deferredPrompt = null; + }); + }, []); + + useEffect(() => { + const getCharacters = async () => { + const response = await fetch( + 'https://gateway.marvel.com/v1/public/characters?ts=alan12345&apikey=e5103c9197bf5466f65433de29139bf9&hash=13b1d704e92de2a50ae29777722bdd75&limit=20&orderBy=-modified' + ); + const data = await response.json(); + + const results = data.data.results; + setCharacters(results); + }; + + getCharacters(); + }, []); + + const fetchMore = async (e) => { + // Fetch more characters + // How? + // Lets limit it by 20, and offset it by the amount loaded already + // E.g. 20, 40, 60 just like pagination :) + // Get the response into json + const response = await fetch( + `https://gateway.marvel.com/v1/public/characters?ts=alan12345&apikey=e5103c9197bf5466f65433de29139bf9&hash=13b1d704e92de2a50ae29777722bdd75&limit=20&offset=${amountLoaded}&orderBy=-modified` + ); + const data = await response.json(); + const results = data.data.results; + + // Set the characters by adding the new results to the current + // Increment the amount loaded by 20 for the next iteration + // Complete the scroll action + setCharacters((prevResults) => [...prevResults, ...results]); + setAmountLoaded((prevAmount) => prevAmount + 20); + e.target.complete(); + }; + + const addToHomeScreen = async () => { + const buttInstall = document.getElementById('buttInstall'); + + console.log('šŸ‘', 'buttInstall-clicked'); + const promptEvent = window.deferredPrompt; + + if (!promptEvent) { + // The deferred prompt isn't available. + return; + } + + // Show the install prompt. + promptEvent.prompt(); + + // Log the result + const result = await promptEvent.userChoice; + console.log('šŸ‘', 'userChoice', result); + + // Reset the deferred prompt variable, since + // prompt() can only be called once. + window.deferredPrompt = null; + + // Hide the install button. + buttInstall.classList.toggle('hidden', true); + }; + + const router = useIonRouter(); + function handleBackClick() { + router.goBack(); + } + + return ( + + + + + handleBackClick()}> + + + + + Marvel Characters + + + + + + + + + setShowToast({ + show: true, + message: 'We could easily add a search button here to search characters.', + }) + } + > + + + + addToHomeScreen()} + > + +   Install App + + + setGrid((grid) => !grid)}> + + + + + + + + + Marvel Characters + + + + + {characters.length > 0 ? ( + characters.map((character, index) => { + if (!character.thumbnail.path.includes('image_not_available')) { + return ; + } else { + return null; + } + }) + ) : ( + + )} + + + + + + + + setShowToast({ show: false, message: '' })} + message={showToast.message} + duration={3500} + color="danger" + /> + + ); +}; + +export default Home; diff --git a/03_source/mobile/src/pages/DemoReactMarvelApp/pages/Info.tsx b/03_source/mobile/src/pages/DemoReactMarvelApp/pages/Info.tsx new file mode 100644 index 0000000..44e5afb --- /dev/null +++ b/03_source/mobile/src/pages/DemoReactMarvelApp/pages/Info.tsx @@ -0,0 +1,95 @@ +import { IonBackButton, IonButton, IonButtons, IonCol, IonContent, IonGrid, IonHeader, IonIcon, IonImg, IonItem, IonLabel, IonPage, IonRow, IonSkeletonText, IonTitle, IonToolbar } from '@ionic/react'; +import { arrowRedoOutline, heartOutline } from 'ionicons/icons'; +import styles from "./ViewCharacter.module.scss"; + +interface Profile { + name: string; + bio: string; + avatar: string; + codeLink: string; + links: Array<{ + name: string; + url: string; + }>; +} + +const Info = (): React.JSX.Element => { + + const profile = { + + name: "Alan Montgomery", + bio: "My name is Alan. I’m a Mobile Team Lead and Senior Developer and have built numerous production, real world mobile apps for local government authorities. I have a real passion and love for sharing my knowledge and expertise with developers wanting to learn and get better at using certain technologies.", + avatar: "/assets/alan.jpg", + codeLink: "https://github.com/alanmontgomery/ionic-react-marvel-app", + links: [ + { + name: "Twitter", + url: "https://twitter.com/93alan" + } + ], + } + return ( + + + + + + + + { navigator.platform.match(/iPhone|iPod|iPad/) && { profile.name } } + + + + + { profile ? + ( + <> + + +
+ { profile.name } +
+
+ + + + +

+ { profile.bio } +

+
+
+ + + + + + Lets connect on Twitter + + + + + + + + + + + Source code for this app + + + + + +
+ + ) + : + + } +
+
+ ); +} + +export default Info; diff --git a/03_source/mobile/src/pages/DemoReactMarvelApp/pages/ViewCharacter.module.scss b/03_source/mobile/src/pages/DemoReactMarvelApp/pages/ViewCharacter.module.scss new file mode 100644 index 0000000..d0a9f20 --- /dev/null +++ b/03_source/mobile/src/pages/DemoReactMarvelApp/pages/ViewCharacter.module.scss @@ -0,0 +1,59 @@ +.characterContainer { + + position: relative; + text-align: center; + color: white; +} + +ion-item { + --padding-start: 0; + --inner-padding-end: 0; +} + +ion-label { + margin-top: 12px; + margin-bottom: 12px; +} + +.characterNameContainer { + + display: flex; + flex-direction: row; + justify-content: center; + position: absolute; + z-index: 99999; + background-color: rgba(0, 0, 0, 0.7); + bottom: 0; + width: 100%; +} + +.characterNameContainer ion-label { + + font-size: 1rem !important; + font-weight: 500; +} + +.characterStats { + + text-align: center; + margin-top: 1.5rem; + margin-bottom: 1.5rem; +} + +.characterStat { + + background-color: var(--ion-color-primary); + padding: 1rem; +} + +.characterStat ion-card-title { + + font-size: 1rem; + --color: white; +} + +.characterStat ion-card-subtitle { + + font-size: 1rem; + --color: white; +} \ No newline at end of file diff --git a/03_source/mobile/src/pages/DemoReactMarvelApp/pages/ViewCharacter.tsx b/03_source/mobile/src/pages/DemoReactMarvelApp/pages/ViewCharacter.tsx new file mode 100644 index 0000000..3fb8156 --- /dev/null +++ b/03_source/mobile/src/pages/DemoReactMarvelApp/pages/ViewCharacter.tsx @@ -0,0 +1,298 @@ +import { useState } from 'react'; +import { + IonBackButton, + IonButton, + IonButtons, + IonCardSubtitle, + IonCardTitle, + IonCol, + IonContent, + IonGrid, + IonHeader, + IonIcon, + IonImg, + IonItem, + IonLabel, + IonPage, + IonRow, + IonSkeletonText, + IonTitle, + IonToast, + IonToolbar, + useIonViewWillEnter, +} from '@ionic/react'; +import { arrowRedoOutline, heartOutline } from 'ionicons/icons'; +import { useParams } from 'react-router'; + +import styles from './ViewCharacter.module.scss'; + +interface Comic { + id: string; + name: string; + image: string; +} + +interface Character { + id: string; + name: string; + description: string; + thumbnail: { + path: string; + extension: string; + }; + comics: { + available: number; + items: Array<{ + name: string; + resourceURI: string; + }>; + }; + stories: { + available: number; + }; + series: { + available: number; + }; + urls: Array<{ + type: string; + url: string; + }>; +} + +const ViewCharacter = (): React.JSX.Element => { + const [character, setCharacter] = useState(); + const [characterComics, setCharacterComics] = useState([]); + const [showToast, setShowToast] = useState<{ show: boolean; message: string }>({ + show: false, + message: '', + }); + const params = useParams(); + + const getComic = async (comicID: string): Promise => { + var comicImageURL = false; + const response = await fetch( + `https://gateway.marvel.com/v1/public/comics/${comicID}?ts=alan12345&apikey=e5103c9197bf5466f65433de29139bf9&hash=13b1d704e92de2a50ae29777722bdd75` + ); + const data = await response.json(); + + if (data) { + if (data.data) { + if (data.data.results.length > 0) { + comicImageURL = + data.data.results[0].thumbnail.path + + '/portrait_incredible.' + + data.data.results[0].thumbnail.extension; + } + } + } + + return comicImageURL; + }; + + const parseComics = async (result: Character): Promise => { + const comics = result.comics.items; + + await comics.forEach(async (comic) => { + const name = comic.name; + const link = comic.resourceURI; + + const linkParts = link.split('/'); + const id = linkParts[linkParts.length - 1]; + const image = await getComic(id); + + setCharacterComics((current) => [ + ...current, + { + id, + name, + image, + }, + ]); + }); + }; + + useIonViewWillEnter(async () => { + const response = await fetch( + `https://gateway.marvel.com/v1/public/characters/${params.id}?ts=alan12345&apikey=e5103c9197bf5466f65433de29139bf9&hash=13b1d704e92de2a50ae29777722bdd75` + ); + const data = await response.json(); + + if (data) { + if (data.data) { + if (data.data.results) { + const result = data.data.results[0]; + setCharacter(result); + parseComics(result); + } + } + } + }); + + return ( + + + + + + + + {navigator.platform.match(/iPhone|iPod|iPad/) && ( + {character && character.name} + )} + + + + setShowToast({ + show: true, + message: + "We could easily add a 'like' button here to add a character to favourites.", + }) + } + > + + + + + + + + {character ? ( + <> + {navigator.platform.match(/iPhone|iPod|iPad/) ? ( + + + + +
+ {character.name} +
+
+
+
+ ) : ( + + +
+ {character.name} +
+
+ )} + + + {character.description && ( + + +

{character.description}

+
+
+ )} + + + +
+ {character.comics.available} + comics +
+
+ + +
+ {character.stories.available} + stories +
+
+ + +
+ {character.series.available} + series +
+
+
+ + {character.urls && ( + <> + {character.urls[1] && ( + + + + + View full profile on Marvel + + + + + + )} + + {character.urls[2] && ( + + + + + View all comics on Marvel + + + + + + )} + + )} + + {characterComics && ( + <> + + + Showing 20 comics... + + + + {characterComics.map((comic, index) => { + if (comic.image && comic.name) { + return ( + + + +
+ {comic.name} +
+
+
+ ); + } + })} +
+ + )} +
+ + ) : ( + + )} +
+ + setShowToast({ show: false, message: '' })} + message={showToast.message} + duration={3500} + color="danger" + /> +
+ ); +}; + +export default ViewCharacter; diff --git a/03_source/mobile/src/pages/DemoReactMarvelApp/style.scss b/03_source/mobile/src/pages/DemoReactMarvelApp/style.scss deleted file mode 100644 index 37c1e1a..0000000 --- a/03_source/mobile/src/pages/DemoReactMarvelApp/style.scss +++ /dev/null @@ -1,103 +0,0 @@ -#about-page { - ion-toolbar { - position: absolute; - - top: 0; - left: 0; - right: 0; - - --background: transparent; - --color: white; - } - - ion-toolbar ion-back-button, - ion-toolbar ion-button, - ion-toolbar ion-menu-button { - --color: white; - } - - .about-header { - position: relative; - - width: 100%; - height: 30%; - } - - .about-header .about-image { - position: absolute; - - top: 0; - left: 0; - bottom: 0; - right: 0; - - background-position: center; - background-size: cover; - background-repeat: no-repeat; - - opacity: 0; - - transition: opacity 500ms ease-in-out; - } - - .about-header .madison { - background-image: url('/assets/WeatherDemo/img/about/madison.jpg'); - } - - .about-header .austin { - background-image: url('/assets/WeatherDemo/img/about/austin.jpg'); - } - - .about-header .chicago { - background-image: url('/assets/WeatherDemo/img/about/chicago.jpg'); - } - - .about-header .seattle { - background-image: url('/assets/WeatherDemo/img/about/seattle.jpg'); - } - - .about-info { - position: relative; - margin-top: -10px; - border-radius: 10px; - background: var(--ion-background-color, #fff); - z-index: 2; // display rounded border above header image - } - - .about-info h3 { - margin-top: 0; - } - - .about-info ion-list { - padding-top: 0; - } - - .about-info p { - line-height: 130%; - - color: var(--ion-color-dark); - } - - .about-info ion-icon { - margin-inline-end: 32px; - } - - /* - * iOS Only - */ - - .ios .about-info { - --ion-padding: 19px; - } - - .ios .about-info h3 { - font-weight: 700; - } -} - -#date-input-popover { - --offset-y: -var(--ion-safe-area-bottom); - - --max-width: 90%; - --width: 336px; -} diff --git a/03_source/mobile/src/pages/DemoReactMarvelApp/theme/variables.scss b/03_source/mobile/src/pages/DemoReactMarvelApp/theme/variables.scss new file mode 100644 index 0000000..b5444bd --- /dev/null +++ b/03_source/mobile/src/pages/DemoReactMarvelApp/theme/variables.scss @@ -0,0 +1,245 @@ +.demo-react-marvel-app { + /* 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; + } + + /* @media (prefers-color-scheme: dark) { */ + /* + * Dark Colors + * ------------------------------------------- + */ + + body { + --ion-color-primary: #ee0000; + --ion-color-primary-rgb: 66, 140, 255; + --ion-color-primary-contrast: #ffffff; + --ion-color-primary-contrast-rgb: 255, 255, 255; + --ion-color-primary-shade: #3a7be0; + --ion-color-primary-tint: #5598ff; + + --ion-color-secondary: #50c8ff; + --ion-color-secondary-rgb: 80, 200, 255; + --ion-color-secondary-contrast: #ffffff; + --ion-color-secondary-contrast-rgb: 255, 255, 255; + --ion-color-secondary-shade: #46b0e0; + --ion-color-secondary-tint: #62ceff; + + --ion-color-tertiary: #6a64ff; + --ion-color-tertiary-rgb: 106, 100, 255; + --ion-color-tertiary-contrast: #ffffff; + --ion-color-tertiary-contrast-rgb: 255, 255, 255; + --ion-color-tertiary-shade: #5d58e0; + --ion-color-tertiary-tint: #7974ff; + + --ion-color-success: #2fdf75; + --ion-color-success-rgb: 47, 223, 117; + --ion-color-success-contrast: #000000; + --ion-color-success-contrast-rgb: 0, 0, 0; + --ion-color-success-shade: #29c467; + --ion-color-success-tint: #44e283; + + --ion-color-warning: #ffd534; + --ion-color-warning-rgb: 255, 213, 52; + --ion-color-warning-contrast: #000000; + --ion-color-warning-contrast-rgb: 0, 0, 0; + --ion-color-warning-shade: #e0bb2e; + --ion-color-warning-tint: #ffd948; + + --ion-color-danger: #ee0000; + --ion-color-danger-rgb: 255, 73, 97; + --ion-color-danger-contrast: #ffffff; + --ion-color-danger-contrast-rgb: 255, 255, 255; + --ion-color-danger-shade: #e04055; + --ion-color-danger-tint: #ff5b71; + + --ion-color-dark: #f4f5f8; + --ion-color-dark-rgb: 244, 245, 248; + --ion-color-dark-contrast: #000000; + --ion-color-dark-contrast-rgb: 0, 0, 0; + --ion-color-dark-shade: #d7d8da; + --ion-color-dark-tint: #f5f6f9; + + --ion-color-medium: #989aa2; + --ion-color-medium-rgb: 152, 154, 162; + --ion-color-medium-contrast: #000000; + --ion-color-medium-contrast-rgb: 0, 0, 0; + --ion-color-medium-shade: #86888f; + --ion-color-medium-tint: #a2a4ab; + + --ion-color-light: #222428; + --ion-color-light-rgb: 34, 36, 40; + --ion-color-light-contrast: #ffffff; + --ion-color-light-contrast-rgb: 255, 255, 255; + --ion-color-light-shade: #1e2023; + --ion-color-light-tint: #383a3e; + } + + /* + * iOS Dark Theme + * ------------------------------------------- + */ + + .ios body { + --ion-background-color: #000000; + --ion-background-color-rgb: 0, 0, 0; + + --ion-text-color: #ffffff; + --ion-text-color-rgb: 255, 255, 255; + + --ion-color-step-50: #0d0d0d; + --ion-color-step-100: #1a1a1a; + --ion-color-step-150: #262626; + --ion-color-step-200: #333333; + --ion-color-step-250: #404040; + --ion-color-step-300: #4d4d4d; + --ion-color-step-350: #595959; + --ion-color-step-400: #666666; + --ion-color-step-450: #737373; + --ion-color-step-500: #808080; + --ion-color-step-550: #8c8c8c; + --ion-color-step-600: #999999; + --ion-color-step-650: #a6a6a6; + --ion-color-step-700: #b3b3b3; + --ion-color-step-750: #bfbfbf; + --ion-color-step-800: #cccccc; + --ion-color-step-850: #d9d9d9; + --ion-color-step-900: #e6e6e6; + --ion-color-step-950: #f2f2f2; + + --ion-item-background: #000000; + + --ion-card-background: #1c1c1d; + } + + .ios ion-modal { + --ion-background-color: var(--ion-color-step-100); + --ion-toolbar-background: var(--ion-color-step-150); + --ion-toolbar-border-color: var(--ion-color-step-250); + } + + /* + * Material Design Dark Theme + * ------------------------------------------- + */ + + .md body { + --ion-background-color: #121212; + --ion-background-color-rgb: 18, 18, 18; + + --ion-text-color: #ffffff; + --ion-text-color-rgb: 255, 255, 255; + + --ion-border-color: #222222; + + --ion-color-step-50: #1e1e1e; + --ion-color-step-100: #2a2a2a; + --ion-color-step-150: #363636; + --ion-color-step-200: #414141; + --ion-color-step-250: #4d4d4d; + --ion-color-step-300: #595959; + --ion-color-step-350: #656565; + --ion-color-step-400: #717171; + --ion-color-step-450: #7d7d7d; + --ion-color-step-500: #898989; + --ion-color-step-550: #949494; + --ion-color-step-600: #a0a0a0; + --ion-color-step-650: #acacac; + --ion-color-step-700: #b8b8b8; + --ion-color-step-750: #c4c4c4; + --ion-color-step-800: #d0d0d0; + --ion-color-step-850: #dbdbdb; + --ion-color-step-900: #e7e7e7; + --ion-color-step-950: #f3f3f3; + + --ion-item-background: #1e1e1e; + + --ion-toolbar-background: #1f1f1f; + + --ion-tab-bar-background: #1f1f1f; + + --ion-card-background: #1e1e1e; + } + /* } */ + + .non-link { + text-decoration: none; + } + + .hidden { + display: none; + } +}