Compare commits

...

15 Commits

Author SHA1 Message Date
louiscklaw
84b223ff60 update, 2025-06-08 19:08:45 +08:00
louiscklaw
fca048074e update public folder, 2025-06-08 19:08:41 +08:00
louiscklaw
bc35e25616 update demo-sliding-profile, 2025-06-08 19:08:01 +08:00
louiscklaw
15f8d2e6aa update demo-shop-app-ui, 2025-06-08 19:08:01 +08:00
louiscklaw
592a099f7b update demo-score-board, 2025-06-08 19:08:01 +08:00
louiscklaw
4c1b30e5c6 update demo-restaurant-finder, 2025-06-08 19:08:00 +08:00
louiscklaw
c765bb49a4 update demo-recipe-app, 2025-06-08 19:08:00 +08:00
louiscklaw
9aeb58379d update demo-react-travel-app, 2025-06-08 19:08:00 +08:00
louiscklaw
6419567005 update demo-react-tabs-menus-custom, 2025-06-08 19:07:48 +08:00
louiscklaw
e2076fe67b update demo-react-switch-tabs, 2025-06-08 19:07:48 +08:00
louiscklaw
766720e075 update demo-react-shop-ui, 2025-06-08 19:07:48 +08:00
louiscklaw
19af60c410 update demo-react-shop, 2025-06-08 19:07:48 +08:00
louiscklaw
ed95621b2f update demo-react-quotes, 2025-06-08 19:07:48 +08:00
louiscklaw
2258fd8fb9 update demo-react-overlay-hooks, 2025-06-08 19:07:48 +08:00
louiscklaw
0f674badd9 update demo-react-onboarding-ui, 2025-06-08 19:07:48 +08:00
270 changed files with 7234 additions and 6877 deletions

View File

@@ -77,12 +77,12 @@ const Chat = () => {
const [toastMessage, setToastMessage] = useState("");
// Refs
const contentRef = useRef();
const contentRef = useRef(null);
const swiperRefs = useRef([]);
const textareaRef = useRef();
const sideRef = useRef();
const sendRef = useRef();
const replyToAnimationRef = useRef();
const textareaRef = useRef(null);
const sideRef = useRef(null);
const sendRef = useRef(null);
const replyToAnimationRef = useRef(null);
const actionSheetButtons = [
{
@@ -104,7 +104,7 @@ const Chat = () => {
icon: alertOutline,
handler: () =>
toaster(
"I haven't implemented unsend :) Simple store update though",
"I haven't implemented unsend :) Simple store update though"
),
},
{
@@ -165,11 +165,11 @@ const Chat = () => {
const chatMessageID = elementID.includes("chatText")
? parseInt(elementID.replace("chatText_", ""))
: elementID.includes("chatTime")
? parseInt(elementID.replace("chatTime_", ""))
: parseInt(elementID.replace("chatBubble_", ""));
? parseInt(elementID.replace("chatTime_", ""))
: parseInt(elementID.replace("chatBubble_", ""));
const chatMessage = chat.filter(
(message) => parseInt(message.id) === parseInt(chatMessageID),
(message) => parseInt(message.id) === parseInt(chatMessageID)
)[0];
setActionMessage(chatMessage);
@@ -278,7 +278,7 @@ const Chat = () => {
replyToMessage,
replyToMessage ? replyToMessage.id : false,
image,
imagePath,
imagePath
);
setMessage("");
@@ -329,7 +329,7 @@ const Chat = () => {
fill="clear"
onClick={() =>
toaster(
"As this is a UI only, video calling wouldn't work here.",
"As this is a UI only, video calling wouldn't work here."
)
}
>
@@ -352,7 +352,7 @@ const Chat = () => {
{chat.map((message, index) => {
const repliedMessage = chat.filter(
(subMessage) =>
parseInt(subMessage.id) === parseInt(message.replyID),
parseInt(subMessage.id) === parseInt(message.replyID)
)[0];
return (
@@ -360,7 +360,9 @@ const Chat = () => {
ref={(ref) => (swiperRefs.current[index] = ref)}
id={`chatBubble_${message.id}`}
key={index}
className={`chat-bubble ${message.sent ? "bubble-sent" : "bubble-received"}`}
className={`chat-bubble ${
message.sent ? "bubble-sent" : "bubble-received"
}`}
{...longPressEvent}
>
<div id={`chatText_${message.id}`}>

View File

@@ -22,7 +22,7 @@ import { useRef } from "react";
import ContactModal from "../components/ContactModal";
const Chats = () => {
const pageRef = useRef();
const pageRef = useRef(null);
const contacts = ContactStore.useState(getContacts);
const latestChats = ChatStore.useState(getChats);
@@ -43,7 +43,7 @@ const Chats = () => {
contacts
.filter((c) => c.id === chat.contact_id)[0]
.name.toLowerCase()
.includes(searchTermLower),
.includes(searchTermLower)
);
setResults(newResults);
} else {

View File

@@ -3,5 +3,28 @@
"semi": true,
"singleQuote": true,
"trailingComma": "es5",
"printWidth": 100
"printWidth": 100,
"overrides": [
{
"files": "src/App.tsx",
"options": {
"printWidth": 160
}
},
{
"files": "src/routes/*",
"options": {
"printWidth": 160
}
},
{
"files": [
"*.html",
"legacy/**/*.js"
],
"options": {
"tabWidth": 4
}
}
]
}

View File

@@ -18,6 +18,7 @@
"@hookform/resolvers": "^4.1.3",
"@ionic/react": "^8.5.0",
"@ionic/react-router": "^8.5.0",
"@ionic/storage": "^4.0.0",
"@mdx-js/react": "^3.1.0",
"@react-hook/window-size": "^3.1.1",
"@types/leaflet": "^1.9.17",
@@ -29,10 +30,12 @@
"pigeon-maps": "^0.22.1",
"pullstate": "^1",
"react": "19.0.0",
"react-canvas-draw": "^1.2.1",
"react-color": "^2.19.3",
"react-confetti": "^6.4.0",
"react-dom": "19.0.0",
"react-hook-form": "^7.55.0",
"react-iconly": "^2.2.10",
"react-leaflet": "^5.0.0",
"react-markdown": "^10.1.0",
"react-qr-code": "^2.0.15",

Binary file not shown.

After

Width:  |  Height:  |  Size: 97 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 930 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

View File

@@ -0,0 +1 @@
<svg width="350" height="140" xmlns="http://www.w3.org/2000/svg" style="background:#f6f7f9"><g fill="none" fill-rule="evenodd"><path fill="#F04141" style="mix-blend-mode:multiply" d="M61.905-34.23l96.194 54.51-66.982 54.512L22 34.887z"/><circle fill="#10DC60" style="mix-blend-mode:multiply" cx="155.5" cy="135.5" r="57.5"/><path fill="#3880FF" style="mix-blend-mode:multiply" d="M208.538 9.513l84.417 15.392L223.93 93.93z"/><path fill="#FFCE00" style="mix-blend-mode:multiply" d="M268.625 106.557l46.332-26.75 46.332 26.75v53.5l-46.332 26.75-46.332-26.75z"/><circle fill="#7044FF" style="mix-blend-mode:multiply" cx="299.5" cy="9.5" r="38.5"/><rect fill="#11D3EA" style="mix-blend-mode:multiply" transform="rotate(-60 148.47 37.886)" x="143.372" y="-7.056" width="10.196" height="89.884" rx="5.098"/><path d="M-25.389 74.253l84.86 8.107c5.498.525 9.53 5.407 9.004 10.905a10 10 0 0 1-.057.477l-12.36 85.671a10.002 10.002 0 0 1-11.634 8.42l-86.351-15.226c-5.44-.959-9.07-6.145-8.112-11.584l13.851-78.551a10 10 0 0 1 10.799-8.219z" fill="#7044FF" style="mix-blend-mode:multiply"/><circle fill="#0CD1E8" style="mix-blend-mode:multiply" cx="273.5" cy="106.5" r="20.5"/></g></svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 129 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 930 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 296 KiB

View File

@@ -0,0 +1 @@
<svg width="350" height="140" xmlns="http://www.w3.org/2000/svg" style="background:#f6f7f9"><g fill="none" fill-rule="evenodd"><path fill="#F04141" style="mix-blend-mode:multiply" d="M61.905-34.23l96.194 54.51-66.982 54.512L22 34.887z"/><circle fill="#10DC60" style="mix-blend-mode:multiply" cx="155.5" cy="135.5" r="57.5"/><path fill="#3880FF" style="mix-blend-mode:multiply" d="M208.538 9.513l84.417 15.392L223.93 93.93z"/><path fill="#FFCE00" style="mix-blend-mode:multiply" d="M268.625 106.557l46.332-26.75 46.332 26.75v53.5l-46.332 26.75-46.332-26.75z"/><circle fill="#7044FF" style="mix-blend-mode:multiply" cx="299.5" cy="9.5" r="38.5"/><rect fill="#11D3EA" style="mix-blend-mode:multiply" transform="rotate(-60 148.47 37.886)" x="143.372" y="-7.056" width="10.196" height="89.884" rx="5.098"/><path d="M-25.389 74.253l84.86 8.107c5.498.525 9.53 5.407 9.004 10.905a10 10 0 0 1-.057.477l-12.36 85.671a10.002 10.002 0 0 1-11.634 8.42l-86.351-15.226c-5.44-.959-9.07-6.145-8.112-11.584l13.851-78.551a10 10 0 0 1 10.799-8.219z" fill="#7044FF" style="mix-blend-mode:multiply"/><circle fill="#0CD1E8" style="mix-blend-mode:multiply" cx="273.5" cy="106.5" r="20.5"/></g></svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 930 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

View File

@@ -0,0 +1 @@
<svg width="350" height="140" xmlns="http://www.w3.org/2000/svg" style="background:#f6f7f9"><g fill="none" fill-rule="evenodd"><path fill="#F04141" style="mix-blend-mode:multiply" d="M61.905-34.23l96.194 54.51-66.982 54.512L22 34.887z"/><circle fill="#10DC60" style="mix-blend-mode:multiply" cx="155.5" cy="135.5" r="57.5"/><path fill="#3880FF" style="mix-blend-mode:multiply" d="M208.538 9.513l84.417 15.392L223.93 93.93z"/><path fill="#FFCE00" style="mix-blend-mode:multiply" d="M268.625 106.557l46.332-26.75 46.332 26.75v53.5l-46.332 26.75-46.332-26.75z"/><circle fill="#7044FF" style="mix-blend-mode:multiply" cx="299.5" cy="9.5" r="38.5"/><rect fill="#11D3EA" style="mix-blend-mode:multiply" transform="rotate(-60 148.47 37.886)" x="143.372" y="-7.056" width="10.196" height="89.884" rx="5.098"/><path d="M-25.389 74.253l84.86 8.107c5.498.525 9.53 5.407 9.004 10.905a10 10 0 0 1-.057.477l-12.36 85.671a10.002 10.002 0 0 1-11.634 8.42l-86.351-15.226c-5.44-.959-9.07-6.145-8.112-11.584l13.851-78.551a10 10 0 0 1 10.799-8.219z" fill="#7044FF" style="mix-blend-mode:multiply"/><circle fill="#0CD1E8" style="mix-blend-mode:multiply" cx="273.5" cy="106.5" r="20.5"/></g></svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -0,0 +1,16 @@
{
"toolbar_background_color": "blue",
"tab_bar_background_color": "blue",
"toolbar_color": "",
"tab_bar_color": "",
"tab_bar_activated_color": "",
"main_color": "",
"light_color": "",
"main_color_tint": "",
"main_color_shade": "",
"light_color_tint": "",
"light_color_shade": ""
}

View File

@@ -0,0 +1,16 @@
{
"toolbar_background_color": "#5f361e",
"tab_bar_background_color": "#5f361e",
"toolbar_color": "#d1bfb5",
"tab_bar_color": "#886551",
"tab_bar_activated_color": "",
"main_color": "#5f361e",
"light_color": "#886551",
"main_color_tint": "#855a41",
"main_color_shade": "#57331e",
"light_color_tint": "#9c7d6b",
"light_color_shade": "#61412f"
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 474 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 359 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 240 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 425 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 279 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 360 KiB

View File

@@ -0,0 +1,16 @@
{
"toolbar_background_color": "#c4b0c4",
"tab_bar_background_color": "#c4b0c4",
"toolbar_color": "#5c4153",
"tab_bar_color": "#917788",
"tab_bar_activated_color": "#5c4153",
"main_color": "#5c4153",
"light_color": "#917788",
"main_color_tint": "#6b5463",
"main_color_shade": "#4d3545",
"light_color_tint": "#a893a1",
"light_color_shade": "#74606d"
}

View File

@@ -0,0 +1,16 @@
{
"toolbar_background_color": "#c93608",
"tab_bar_background_color": "#c93608",
"toolbar_color": "",
"tab_bar_color": "#852506",
"tab_bar_activated_color": "",
"main_color": "#c93608",
"light_color": "#c95834",
"main_color_tint": "#aa614a",
"main_color_shade": "#692611",
"light_color_tint": "#d67151",
"light_color_shade": "#a85439"
}

View File

@@ -0,0 +1,16 @@
{
"toolbar_background_color": "green",
"tab_bar_background_color": "green",
"toolbar_color": "",
"tab_bar_color": "",
"tab_bar_activated_color": "",
"main_color": "",
"light_color": "",
"main_color_tint": "",
"main_color_shade": "",
"light_color_tint": "",
"light_color_shade": ""
}

View File

@@ -0,0 +1,16 @@
{
"toolbar_background_color": "#336b36",
"tab_bar_background_color": "#336b36",
"toolbar_color": "white",
"tab_bar_color": "#1c421d",
"tab_bar_activated_color": "white",
"main_color": "#336b36",
"light_color": "#517953",
"main_color_tint": "#497a4b",
"main_color_shade": "#305832",
"light_color_tint": "#738574",
"light_color_shade": "#485849"
}

View File

@@ -0,0 +1,16 @@
{
"toolbar_background_color": "#7baec7",
"tab_bar_background_color": "#7baec7",
"toolbar_color": "",
"tab_bar_color": "#49758b",
"tab_bar_activated_color": "",
"main_color": "#7baec7",
"light_color": "#90bbcf",
"main_color_tint": "#96c0d5",
"main_color_shade": "#6b93a7",
"light_color_tint": "#c3e2f1",
"light_color_shade": "#89aec0"
}

View File

@@ -0,0 +1,16 @@
{
"toolbar_background_color": "#fd8f38",
"tab_bar_background_color": "#fd8f38",
"toolbar_color": "#815208",
"tab_bar_color": "#ffb67c",
"tab_bar_activated_color": "#815208",
"main_color": "#e49200",
"light_color": "#ffb67c",
"main_color_tint": "#e6ae4b",
"main_color_shade": "#b4780c",
"light_color_tint": "#fad4b6",
"light_color_shade": "#ff9c4e"
}

View File

@@ -0,0 +1,16 @@
{
"toolbar_background_color": "red",
"tab_bar_background_color": "red",
"toolbar_color": "",
"tab_bar_color": "",
"tab_bar_activated_color": "",
"main_color": "",
"light_color": "",
"main_color_tint": "",
"main_color_shade": "",
"light_color_tint": "",
"light_color_shade": ""
}

View File

@@ -0,0 +1,16 @@
{
"toolbar_background_color": "blue",
"tab_bar_background_color": "blue",
"toolbar_color": "",
"tab_bar_color": "",
"tab_bar_activated_color": "",
"main_color": "",
"light_color": "",
"main_color_tint": "",
"main_color_shade": "",
"light_color_tint": "",
"light_color_shade": ""
}

View File

@@ -0,0 +1,16 @@
{
"toolbar_background_color": "#5f361e",
"tab_bar_background_color": "#5f361e",
"toolbar_color": "#d1bfb5",
"tab_bar_color": "#886551",
"tab_bar_activated_color": "",
"main_color": "#5f361e",
"light_color": "#886551",
"main_color_tint": "#855a41",
"main_color_shade": "#57331e",
"light_color_tint": "#9c7d6b",
"light_color_shade": "#61412f"
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 474 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 359 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 240 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 425 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 279 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 360 KiB

View File

@@ -0,0 +1,16 @@
{
"toolbar_background_color": "#c4b0c4",
"tab_bar_background_color": "#c4b0c4",
"toolbar_color": "#5c4153",
"tab_bar_color": "#917788",
"tab_bar_activated_color": "#5c4153",
"main_color": "#5c4153",
"light_color": "#917788",
"main_color_tint": "#6b5463",
"main_color_shade": "#4d3545",
"light_color_tint": "#a893a1",
"light_color_shade": "#74606d"
}

View File

@@ -0,0 +1,16 @@
{
"toolbar_background_color": "#c93608",
"tab_bar_background_color": "#c93608",
"toolbar_color": "",
"tab_bar_color": "#852506",
"tab_bar_activated_color": "",
"main_color": "#c93608",
"light_color": "#c95834",
"main_color_tint": "#aa614a",
"main_color_shade": "#692611",
"light_color_tint": "#d67151",
"light_color_shade": "#a85439"
}

View File

@@ -0,0 +1,16 @@
{
"toolbar_background_color": "green",
"tab_bar_background_color": "green",
"toolbar_color": "",
"tab_bar_color": "",
"tab_bar_activated_color": "",
"main_color": "",
"light_color": "",
"main_color_tint": "",
"main_color_shade": "",
"light_color_tint": "",
"light_color_shade": ""
}

View File

@@ -0,0 +1,16 @@
{
"toolbar_background_color": "#336b36",
"tab_bar_background_color": "#336b36",
"toolbar_color": "white",
"tab_bar_color": "#1c421d",
"tab_bar_activated_color": "white",
"main_color": "#336b36",
"light_color": "#517953",
"main_color_tint": "#497a4b",
"main_color_shade": "#305832",
"light_color_tint": "#738574",
"light_color_shade": "#485849"
}

View File

@@ -0,0 +1,16 @@
{
"toolbar_background_color": "#7baec7",
"tab_bar_background_color": "#7baec7",
"toolbar_color": "",
"tab_bar_color": "#49758b",
"tab_bar_activated_color": "",
"main_color": "#7baec7",
"light_color": "#90bbcf",
"main_color_tint": "#96c0d5",
"main_color_shade": "#6b93a7",
"light_color_tint": "#c3e2f1",
"light_color_shade": "#89aec0"
}

View File

@@ -0,0 +1,16 @@
{
"toolbar_background_color": "#fd8f38",
"tab_bar_background_color": "#fd8f38",
"toolbar_color": "#815208",
"tab_bar_color": "#ffb67c",
"tab_bar_activated_color": "#815208",
"main_color": "#e49200",
"light_color": "#ffb67c",
"main_color_tint": "#e6ae4b",
"main_color_shade": "#b4780c",
"light_color_tint": "#fad4b6",
"light_color_shade": "#ff9c4e"
}

View File

@@ -0,0 +1,16 @@
{
"toolbar_background_color": "red",
"tab_bar_background_color": "red",
"toolbar_color": "",
"tab_bar_color": "",
"tab_bar_activated_color": "",
"main_color": "",
"light_color": "",
"main_color_tint": "",
"main_color_shade": "",
"light_color_tint": "",
"light_color_shade": ""
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 930 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 772 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 298 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 795 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 822 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 736 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 590 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 611 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 750 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 236 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 465 KiB

View File

@@ -0,0 +1 @@
<svg width="350" height="140" xmlns="http://www.w3.org/2000/svg" style="background:#f6f7f9"><g fill="none" fill-rule="evenodd"><path fill="#F04141" style="mix-blend-mode:multiply" d="M61.905-34.23l96.194 54.51-66.982 54.512L22 34.887z"/><circle fill="#10DC60" style="mix-blend-mode:multiply" cx="155.5" cy="135.5" r="57.5"/><path fill="#3880FF" style="mix-blend-mode:multiply" d="M208.538 9.513l84.417 15.392L223.93 93.93z"/><path fill="#FFCE00" style="mix-blend-mode:multiply" d="M268.625 106.557l46.332-26.75 46.332 26.75v53.5l-46.332 26.75-46.332-26.75z"/><circle fill="#7044FF" style="mix-blend-mode:multiply" cx="299.5" cy="9.5" r="38.5"/><rect fill="#11D3EA" style="mix-blend-mode:multiply" transform="rotate(-60 148.47 37.886)" x="143.372" y="-7.056" width="10.196" height="89.884" rx="5.098"/><path d="M-25.389 74.253l84.86 8.107c5.498.525 9.53 5.407 9.004 10.905a10 10 0 0 1-.057.477l-12.36 85.671a10.002 10.002 0 0 1-11.634 8.42l-86.351-15.226c-5.44-.959-9.07-6.145-8.112-11.584l13.851-78.551a10 10 0 0 1 10.799-8.219z" fill="#7044FF" style="mix-blend-mode:multiply"/><circle fill="#0CD1E8" style="mix-blend-mode:multiply" cx="273.5" cy="106.5" r="20.5"/></g></svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -54,49 +54,34 @@ import Tutorial from './pages/Tutorial';
import HomeOrTutorial from './components/HomeOrTutorial';
import { Schedule } from './models/Schedule';
import RedirectToLogin from './components/RedirectToLogin';
import EventDetail from './pages/EventDetail';
import EventList from './pages/EventList';
import MemberProfile from './pages/MemberProfile';
import Settings from './pages/Settings';
import NotImplemented from './pages/NotImplemented';
import ChangeLanguage from './pages/ChangeLanguage';
import ServiceAgreement from './pages/ServiceAgreement';
import paths from './paths';
import PrivacyAgreement from './pages/PrivacyAgreement';
import AppRoute from './AppRoute';
//
// TODO: resume DemoReactShop
// import DemoReactShop from './pages/DemoReactShop';
import DemoWeatherApp from './pages/DemoWeatherApp';
import DemoClubHouse from './pages/DemoClubHouse';
import DemoScoreBoard from './pages/DemoScoreBoard';
import DemoQuoteApp from './pages/DemoQuoteApp';
import DemoQrScanner from './pages/DemoQrScanner';
// TODO: remove obsoleted DemoWeatherApp
// import DemoWeatherApp from './pages/DemoWeatherApp';
// DemoShopAppUi
import DemoShopAppUi from './pages/DemoShopAppUi';
// DemoDictionaryApp
import DemoDictionaryApp from './pages/DemoDictionaryApp';
// demo-recipe-app
import DemoRecipeApp from './pages/DemoRecipeApp';
// DemoSlidingProfile
import DemoSlidingProfile from './pages/DemoSlidingProfile';
// DemoQuizApp
import DemoQuizApp from './pages/DemoQuizApp';
import DemoBlogPostUi from './pages/DemoBlogPostUi';
import DemoReactTravelApp from './pages/DemoReactTravelApp';
import DemoPinterestFloatingTabBar from './pages/DemoPinterestFloatingTabBar';
import DemoRestaurantFinder from './pages/DemoRestaurantFinder';
import DemoReactOverlayHooks from './pages/DemoReactOverlayHooks';
import DemoReactSwitchTabs from './pages/DemoReactSwitchTabs';
import DemoReactPollApp from './pages/DemoReactPollApp';
import DemoReactWhatsAppClone from './pages/DemoReactWhatsAppClone';
import Demo2FaExample from './pages/Demo2FaExample';
import DemoAccordionTutorial from './pages/DemoAccordionTutorial';
import DemoBankingUi from './pages/DemoBankingUi';
import DemoCapacitorGoogleMapsTutorial from './pages/DemoCapacitorGoogleMapsTutorial';
import DemoColorTutorial from './pages/DemoColorTutorial';
//
// import DemoReactMarvelApp from './pages/DemoReactMarvelApp';
// import DemoReactOnboardingUI from './pages/DemoReactOnboardingUI';
// import DemoReactTabsMenusCustom from './pages/DemoReactTabsMenusCustom';
// import DemoReactThemeSwitcher from './pages/DemoReactThemeSwitcher';
// import DemoSkeletonText from './pages/DemoSkeletonText';
// import DemoStickyBottomSheetExample from './pages/DemoStickyBottomSheetExample';
// import DemoStorageExample from './pages/DemoStorageExample';
// import DemoSwiperjsTutorial from './pages/DemoSwiperjsTutorial';
// TODO: SCSS of this directory will alter the main page
import AppDemoRoute from './routes/DemoRoute';
import Settings from './pages/Settings';
setupIonicReact();
@@ -122,14 +107,7 @@ interface DispatchProps {
interface IonicAppProps extends StateProps, DispatchProps {}
const IonicApp: React.FC<IonicAppProps> = ({
darkMode,
schedule,
setIsLoggedIn,
setUsername,
loadConfData,
loadUserData,
}) => {
const IonicApp: React.FC<IonicAppProps> = ({ darkMode, schedule, setIsLoggedIn, setUsername, loadConfData, loadUserData }) => {
useEffect(() => {
loadUserData();
loadConfData();
@@ -153,98 +131,28 @@ const IonicApp: React.FC<IonicAppProps> = ({
<AppRoute />
<Route path="/tabs" render={() => <MainTabs />} />
<Route path={paths.DEMO_WEATHER_APP} render={() => <DemoWeatherApp />} />
{/* */}
{/* */}
{/* */}
{/* */}
{/* */}
{/* */}
{/* */}
{/* */}
<AppDemoRoute />
{/* */}
<Route path={paths.DEMO_ACCORDION_TUTORIAL} render={() => <DemoAccordionTutorial />} />
{/* */}
{/* */}
{/* */}
{/* */}
{/* */}
{/* */}
<Route path={paths.DEMO_BANKING_UI} render={() => <DemoBankingUi />} />
<Route
path={paths.DEMO_CAPACITOR_GOOGLE_MAPS_TUTORIAL}
render={() => <DemoCapacitorGoogleMapsTutorial />}
/>
<Route path={paths.DEMO_COLOR_TUTORIAL} render={() => <DemoColorTutorial />} />
{/*
<Route path={paths.DEMO_ECOMMERCE_EXAMPLE} render={() => <DemoEcommerceExample />} />
<Route path={paths.DEMO_FACEBOOK_CLONE} render={() => <DemoFacebookClone />} />
<Route path={paths.DEMO_FAST_FOOD_APP} render={() => <DemoFastFoodApp />} />
<Route path={paths.DEMO_FLOATING_TABS} render={() => <DemoFloatingTabs />} />
<Route path={paths.DEMO_INSTAGRAM_CLONE} render={() => <DemoInstagramClone />} />
<Route path={paths.DEMO_KANBAN_BOARD} render={() => <DemoKanbanBoard />} />
<Route path={paths.DEMO_ORDERING_APP} render={() => <DemoOrderingApp />} />
<Route path={paths.DEMO_PROFILE_EXAMPLE} render={() => <DemoProfileExample />} />
<Route path={paths.DEMO_PULLSTATE_TUTORIAL} render={() => <DemoPullstateTutorial />} />
<Route path={paths.DEMO_REACT_ADD_TO_CART} render={() => <DemoReactAddToCart />} />
<Route path={paths.DEMO_REACT_CALCULATOR} render={() => <DemoReactCalculator />} />
<Route path={paths.DEMO_REACT_DRAWING_CANVAS} render={() => <DemoReactDrawingCanvas />} />
<Route path={paths.DEMO_REACT_HOOK_FORM_EXAMPLE} render={() => <DemoReactHookFormExample />} />
<Route path={paths.DEMO_REACT_ITEM_LIST} render={() => <DemoReactItemList />} />
<Route path={paths.DEMO_REACT_LIFECYCLES} render={() => <DemoReactLifecycles />} />
<Route path={paths.DEMO_REACT_LOGIN} render={() => <DemoReactLogin />} />
<Route path={paths.DEMO_REACT_MARVEL_APP} render={() => <DemoReactMarvelApp />} />
<Route path={paths.DEMO_REACT_MOVIE_APP_WITH_ALGOLIA} render(() => <DemoReactMovieAppWithAlgolia />} />
<Route path={paths.DEMO_REACT_NOTES} render={() => <DemoReactNotes />} />
<Route path={paths.DEMO_REACT_ONBOARDING_UI} render={() => <DemoReactOnboardingUI />} />
<Route path={paths.DEMO_REACT_PROFILE_DASHBOARD_UI} render(() => <DemoReactProfileDashboardUI />} />
<Route path={paths.DEMO_REACT_QR_CODE} render={() => <DemoReactQRCode />} />
<Route path={paths.DEMO_REACT_QUOTES} render(() => <DemoReactQuotes />} />
<Route path={paths.DEMO_REACT_SHOP_UI} render(() => <DemoReactShopUI />} />
<Route path={paths.DEMO_REACT_TABS_MENUS_CUSTOM} render(() => <DemoReactTabsMenusCustom />} />
<Route path={paths.DEMO_REACT_THEME_SWITCHER} render(() => <DemoReactThemeSwitcher />} />
<Route path={paths.DEMO_REACT_WHATSAPP_CLONE} render(() => <DemoReactWhatsAppClone />} />
<Route path={paths.DEMO_SKELETON_TEXT} render(() => <DemoSkeletonText />} />
<Route path={paths.DEMO_STICKY_BOTTOM_SHEET_EXAMPLE} render(() => <DemoStickyBottomSheetExample />} />
<Route path={paths.DEMO_STORAGE_EXAMPLE} render(() => <DemoStorageExample />} />
<Route path={paths.DEMO_SWIPERJS_TUTORIAL} render(() => <DemoSwiperjsTutorial />} />
<Route path={paths.DEMO_WEATHER_APP_UI} render(() => <DemoWeatherAppUI />} />
*/}
<Route path={paths.DEMO_2FA_EXAMPLE} render={() => <Demo2FaExample />} />
{/* have problemx` */}
{/* <Route path={paths.DEMO_REACT_WHATSAPP_CLONE} render={() => <DemoReactWhatsAppClone />} /> */}
<Route path={paths.DEMO_REACT_POLL_APP} render={() => <DemoReactPollApp />} />
<Route path={paths.DEMO_BLOG_POST_UI} render={() => <DemoBlogPostUi />} />
<Route path={paths.DEMO_CLUB_HOUSE} render={() => <DemoClubHouse />} />
<Route path={paths.DEMO_DICTIONARY_APP} render={() => <DemoDictionaryApp />} />
<Route
path={paths.DEMO_PINTEREST_FLOATING_TAB_BAR}
render={() => <DemoPinterestFloatingTabBar />}
/>
<Route path={paths.DEMO_QR_SCANNER} render={() => <DemoQrScanner />} />
<Route path={paths.DEMO_QUIZ_APP} render={() => <DemoQuizApp />} />
<Route path={paths.DEMO_QUOTE_APP} render={() => <DemoQuoteApp />} />
<Route path={paths.DEMO_REACT_OVERLAY_HOOKS} render={() => <DemoReactOverlayHooks />} />
<Route path={paths.DEMO_REACT_POLL_APP} render={() => <DemoReactPollApp />} />
{/* TODO: need update to @capacitor/barcode-scanner */}
{/* <Route path={paths.DEMO_REACT_QR_CODE} render={() => <DemoReactQrCode />} /> */}
{/* TODO: resume DemoReactShop */}
{/* <Route path={paths.DEMO_REACT_SHOP} render={() => <DemoReactShop />} /> */}
<Route path={paths.DEMO_REACT_SWITCH_TABS} render={() => <DemoReactSwitchTabs />} />
<Route path={paths.DEMO_REACT_TRAVEL_APP} render={() => <DemoReactTravelApp />} />
<Route path={paths.DEMO_RECIPE_APP} render={() => <DemoRecipeApp />} />
<Route path={paths.DEMO_RESTAURANT_FINDER} render={() => <DemoRestaurantFinder />} />
<Route path={paths.DEMO_SCORE_BOARD} render={() => <DemoScoreBoard />} />
<Route path={paths.DEMO_SHOP_APP_UI} render={() => <DemoShopAppUi />} />
<Route path={paths.DEMO_SLIDING_PROFILE} render={() => <DemoSlidingProfile />} />
{/* have problemx` */}
{/* <Route path={paths.DEMO_REACT_WHATSAPP_CLONE} render={() => <DemoReactWhatsAppClone />} /> */}
{/* TODO: scss will alter the main page, */}
{/* <Route path={paths.DEMO_REACT_MARVEL_APP} render={() => <DemoReactMarvelApp />} /> */}
{/* TODO: update ionslide */}
{/* <Route path={paths.DEMO_REACT_ONBOARDING_UI} render={() => <DemoReactOnboardingUI />} /> */}
{/* TODO: place a whatsapp clone */}
{/* <Route path={paths.DEMO_REACT_WHATSAPP_CLONE} render={() => <DemoReactWhatsAppClone />} /> */}
<Route path="/account" component={Account} />
<Route path="/login" component={Login} />
@@ -253,6 +161,7 @@ const IonicApp: React.FC<IonicAppProps> = ({
<Route path="/signup" component={Signup} />
<Route path="/support" component={Support} />
<Route path="/tutorial" component={Tutorial} />
<Route path="/settings" component={Settings} />
<Route
path="/logout"

View File

@@ -6,7 +6,7 @@ import { Route } from 'react-router';
import NotImplemented from './pages/NotImplemented';
import EventDetail from './pages/EventDetail';
import MemberProfile from './pages/MemberProfile';
import paths from './paths';
import PATHS from './PATHS';
import Settings from './pages/Settings';
import ChangeLanguage from './pages/ChangeLanguage';
import ServiceAgreement from './pages/ServiceAgreement';
@@ -28,10 +28,10 @@ const AppRoute: React.FC = () => {
{/* <Route path="/tabs/speakers/:id" component={SpeakerDetail} exact={true} /> */}
{/* */}
<Route exact={true} path={paths.SETTINGS} component={Settings} />
<Route exact={true} path={paths.CHANGE_LANGUAGE} component={ChangeLanguage} />
<Route exact={true} path={paths.SERVICE_AGREEMENT} component={ServiceAgreement} />
<Route exact={true} path={paths.PRIVACY_AGREEMENT} component={PrivacyAgreement} />
<Route exact={true} path={PATHS.SETTINGS} component={Settings} />
<Route exact={true} path={PATHS.CHANGE_LANGUAGE} component={ChangeLanguage} />
<Route exact={true} path={PATHS.SERVICE_AGREEMENT} component={ServiceAgreement} />
<Route exact={true} path={PATHS.PRIVACY_AGREEMENT} component={PrivacyAgreement} />
</>
);
};

View File

@@ -0,0 +1,81 @@
const PATHS = {
NOT_IMPLEMENTED: '/not_implemented',
SETTINGS: '/settings',
CHANGE_LANGUAGE: '/change_language',
SERVICE_AGREEMENT: '/service_agreement',
PRIVACY_AGREEMENT: '/privacy_agreement',
SIGN_IN: '/mylogin',
//
ORDER_DETAIL: '/order_detail/:id',
getOrderDetail: (id: string) => `/order_detail/${id}`,
//
TAB_NOT_IMPLEMENTED: '/tabs/not_implemented',
EVENT_LIST: `/tabs/events`,
MESSAGE_LIST: `/tabs/messages`,
NEARBY_LIST: '/tabs/nearby',
ORDERS_LIST: '/tabs/orders',
FAVOURITES_LIST: `/tabs/favourites`,
PROFILE: '/tabs/my_profile',
//
// DEMO_WEATHER_APP: '/demo-weather-app',
DEMO_WEATHER_APP_UI: '/demo-weather-app-ui',
//
DEMO_2FA_EXAMPLE: '/demo-2fa-example',
DEMO_ACCORDION_TUTORIAL: '/demo-accordion-tutorial',
DEMO_BANKING_UI: '/demo-banking-ui',
DEMO_BLOG_POST_UI: '/demo-blog-post-ui',
DEMO_CAPACITOR_GOOGLE_MAPS_TUTORIAL: '/demo-capacitor-google-maps-tutorial',
DEMO_CLUB_HOUSE: '/demo-club-house',
DEMO_COLOR_TUTORIAL: '/demo-color-tutorial',
DEMO_DICTIONARY_APP: '/demo-dictionary-app',
DEMO_ECOMMERCE_EXAMPLE: '/demo-ecommerce-example',
DEMO_FACEBOOK_CLONE: '/demo-facebook-clone',
DEMO_FAST_FOOD_APP: '/demo-fast-food-app',
DEMO_FLOATING_TABS: '/demo-floating-tabs',
DEMO_INSTAGRAM_CLONE: '/demo-instagram-clone',
DEMO_KANBAN_BOARD: '/demo-kanban-board',
DEMO_ORDERING_APP: '/demo-ordering-app',
DEMO_PAGE: '/tabs/demo-list',
DEMO_PINTEREST_FLOATING_TAB_BAR: '/demo-pinterest-floating-tab-bar',
DEMO_PROFILE_EXAMPLE: '/demo-profile-example',
DEMO_PULLSTATE_TUTORIAL: '/demo-pullstate-tutorial',
DEMO_QUIZ_APP: '/demo-quiz-app',
DEMO_QUOTE_APP: '/demo-quote-app',
DEMO_REACT_ADD_TO_CART: '/demo-react-add-to-cart',
DEMO_REACT_CALCULATOR: '/demo-react-calculator',
DEMO_REACT_DRAWING_CANVAS: '/demo-react-drawing-canvas',
DEMO_REACT_HOOK_FORM_EXAMPLE: '/demo-react-hook-form-example',
DEMO_REACT_ITEM_LIST: '/demo-react-item-list',
DEMO_REACT_LIFECYCLES: '/demo-react-lifecycles',
DEMO_REACT_LOGIN: '/demo-react-login',
DEMO_REACT_MARVEL_APP: '/demo-react-marvel-app',
DEMO_REACT_MOVIE_APP_WITH_ALGOLIA: '/demo-react-movie-app-with-algolia',
DEMO_REACT_NOTES: '/demo-react-notes',
DEMO_REACT_ONBOARDING_UI: '/demo-react-onboarding-ui',
DEMO_REACT_OVERLAY_HOOKS: '/demo-react-overlay-hooks',
DEMO_REACT_POLL_APP: '/demo-react-poll-app',
DEMO_REACT_PROFILE_DASHBOARD_UI: '/demo-react-profile-dashboard-ui',
DEMO_REACT_QR_CODE: '/demo-react-qr-code',
DEMO_QR_SCANNER: '/demo-qr-scanner',
DEMO_REACT_QUOTES: '/demo-react-quotes',
DEMO_REACT_SHOP_UI: '/demo-react-shop-ui',
DEMO_REACT_SHOP: '/demo-react-shop',
DEMO_REACT_SWITCH_TABS: '/demo-react-switch-tabs',
DEMO_REACT_TABS_MENUS_CUSTOM: '/demo-react-tabs-menus-custom',
DEMO_REACT_THEME_SWITCHER: '/demo-react-theme-switcher',
DEMO_REACT_TRAVEL_APP: '/demo-react-travel-app',
DEMO_REACT_WHATSAPP_CLONE: '/demo-react-whatsapp-clone',
DEMO_RECIPE_APP: '/demo-recipe-app',
DEMO_RESTAURANT_FINDER: '/demo-restaurant-finder',
DEMO_SCORE_BOARD: '/demo-score-board',
DEMO_SHOP_APP_UI: '/demo-shop-app-ui',
DEMO_SKELETON_TEXT: '/demo-skeleton-text',
DEMO_SLIDING_PROFILE: '/demo-sliding-profile',
DEMO_STICKY_BOTTOM_SHEET_EXAMPLE: '/demo-sticky-bottom-sheet-example',
DEMO_STORAGE_EXAMPLE: '/demo-storage-example',
};
export default PATHS;

View File

@@ -2,7 +2,7 @@ import { Route } from 'react-router';
import NotImplemented from './pages/NotImplemented';
import EventDetail from './pages/EventDetail';
import MemberProfile from './pages/MemberProfile';
import paths from './paths';
import PATHS from './PATHS';
import MembersNearByList from './pages/MembersNearByList';
import OrderList from './pages/OrderList';
import MessageList from './pages/MessageList';
@@ -17,25 +17,25 @@ import DemoList from './pages/DemoList';
const TabAppRoute: React.FC = () => {
return (
<>
<Route path={paths.TAB_NOT_IMPLEMENTED} component={NotImplemented} />
<Route path={PATHS.TAB_NOT_IMPLEMENTED} component={NotImplemented} />
{/* */}
<Route path={paths.NEARBY_LIST} render={() => <MembersNearByList />} exact={true} />
<Route path={PATHS.NEARBY_LIST} render={() => <MembersNearByList />} exact={true} />
{/* */}
<Route path={paths.ORDERS_LIST} render={() => <OrderList />} exact={true} />
<Route path={PATHS.ORDERS_LIST} render={() => <OrderList />} exact={true} />
{/* */}
<Route path={paths.MESSAGE_LIST} render={() => <MessageList />} exact={true} />
<Route path={PATHS.MESSAGE_LIST} render={() => <MessageList />} exact={true} />
{/* */}
<Route path={paths.FAVOURITES_LIST} render={() => <Favourites />} exact={true} />
<Route path={PATHS.FAVOURITES_LIST} render={() => <Favourites />} exact={true} />
{/* */}
<Route path={paths.EVENT_LIST} render={() => <EventList />} exact={true} />
<Route path={PATHS.EVENT_LIST} render={() => <EventList />} exact={true} />
{/* */}
<Route path={paths.PROFILE} render={() => <MyProfile />} exact={true} />
<Route path={PATHS.PROFILE} render={() => <MyProfile />} exact={true} />
{/* */}
<Route path="/tabs/demo-list" render={() => <DemoList />} exact={true} />

View File

@@ -3,7 +3,7 @@
import axios from '../../lib/axios';
import { JWT_STORAGE_KEY } from './constant.js';
import paths from '../../paths.js';
import PATHS from '../../PATHS.js';
// ----------------------------------------------------------------------
@@ -60,7 +60,7 @@ export function tokenExpired(exp: number) {
try {
alert('Token expired!');
sessionStorage.removeItem(JWT_STORAGE_KEY);
window.location.href = paths.SIGN_IN;
window.location.href = PATHS.SIGN_IN;
} catch (error) {
console.error('Error during token expiration:', error);
throw error;

View File

@@ -0,0 +1,59 @@
import { IonSlide, IonButton, IonGrid, IonRow, IonCol } from '@ionic/react';
import '../pages/Home.css';
interface OnboardingSlideProps {
image: string;
mainSlide?: boolean;
finalSlide?: boolean;
title: string;
text: string;
lastSlide?: boolean;
sliderRef: React.RefObject<any>;
}
const OnboardingSlide = ({
image,
mainSlide = false,
finalSlide = false,
title,
text,
lastSlide,
sliderRef,
}: OnboardingSlideProps): React.JSX.Element => {
return (
<IonSlide>
<IonGrid className="ion-justify-content-center ion-align-items-center ion-align-self-center">
<IonRow className="slide-content-container">
<IonCol size="10" className="slide-content">
<img src={image} className={mainSlide && 'slide-main-image'} />
<h1>{title}</h1>
<p>{text}</p>
{mainSlide && (
<IonButton
expand="block"
fill="outline"
onClick={() => sliderRef.current.slideNext()}
>
Get started &rarr;
</IonButton>
)}
{finalSlide && (
<>
<IonButton expand="block" fill="solid">
Register
</IonButton>
<IonButton expand="block" fill="outline">
Login
</IonButton>
</>
)}
</IonCol>
</IonRow>
</IonGrid>
</IonSlide>
);
};
export default OnboardingSlide;

View File

@@ -0,0 +1,52 @@
ion-slides {
height: 100%;
}
.slide-grid {
height: 100%;
}
.slide-main-image {
height: 5rem !important;
}
.slide-buttons {
position: absolute;
bottom: 2rem;
z-index: 10;
display: flex;
flex-direction: row;
justify-content: center;
width: 100%;
align-items: center;
align-content: center;
}
.slide-content-container {
margin-top: -4rem;
}
.slide-content {
margin: 0 auto;
/* margin-top: 5rem; */
color: var(--ion-color-primary);
/* background-color: var(--ion-color-primary); */
/* color: white; */
border: 2px solid rgb(228, 228, 228);
border-radius: 15px;
padding: 3rem;
/* padding-left: 3rem; */
/* padding-right: 3rem; */
}
.slide-content p {
color: rgb(161, 161, 161);
}

View File

@@ -0,0 +1,89 @@
import { IonButton, IonContent, IonIcon, IonPage, IonRow, IonSlides } from '@ionic/react';
import { arrowBack, arrowForward } from 'ionicons/icons';
import { useRef, useState } from 'react';
import OnboardingSlide from '../components/OnboardingSlide';
import './Home.css';
interface SlideContent {
image: string;
mainSlide?: boolean;
finalSlide?: boolean;
title: string;
text: string;
}
const Home = (): React.JSX.Element => {
const sliderRef = useRef<HTMLIonSlidesElement>(null);
const [lastSlide, setLastSlide] = useState(false);
const [firstSlide, setFirstSlide] = useState(true);
const slideContent: SlideContent[] = [
{
image: '/assets/applogo1.png',
mainSlide: true,
title: 'Ionic Onboarding UI',
text: 'Share moments with your followers and experience memorable captures',
},
{
image: '/assets/1sub.png',
title: 'Capture',
text: 'Capture that perfect moment in your life',
},
{
image: '/assets/2sub.png',
title: 'Organize',
text: 'Organize photos exactly how you want them',
},
{
image: '/assets/3sub.png',
title: 'Share',
finalSlide: true,
text: 'Are you ready to share your special moments online with the world?',
},
];
const checkSlides = async () => {
if (!sliderRef.current) return;
const isLastSlide = await sliderRef.current.isEnd();
const isFirstSlide = await sliderRef.current.isBeginning();
setLastSlide(isLastSlide);
setFirstSlide(isFirstSlide);
};
return (
<IonPage>
<IonContent fullscreen>
<IonSlides
onIonSlideWillChange={checkSlides}
pager={true}
ref={sliderRef}
id="slider"
options={{ slidesPerView: 'auto', zoom: true, grabCursor: true }}
>
{slideContent.map((slide, index) => {
return (
<OnboardingSlide key={index} {...slide} lastSlide={lastSlide} sliderRef={sliderRef} />
);
})}
</IonSlides>
<IonRow className="slide-buttons">
{!firstSlide && (
<IonButton fill="clear" onClick={() => sliderRef.current?.slidePrev()}>
<IonIcon icon={arrowBack} />
</IonButton>
)}
{!lastSlide && (
<IonButton fill="clear" onClick={() => sliderRef.current?.slideNext()}>
<IonIcon icon={arrowForward} />
</IonButton>
)}
</IonRow>
</IonContent>
</IonPage>
);
};
export default Home;

View File

@@ -0,0 +1,82 @@
/* 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;
}
.swiper-pagination {
margin-bottom: 1rem;
}

View File

@@ -0,0 +1,113 @@
ion-menu ion-content {
--background: var(--ion-item-background, var(--ion-background-color, #fff));
}
ion-menu.md ion-content {
--padding-start: 8px;
--padding-end: 8px;
--padding-top: 20px;
--padding-bottom: 20px;
}
ion-menu.md ion-list {
padding: 20px 0;
}
ion-menu.md ion-note {
margin-bottom: 30px;
}
ion-menu.md ion-list-header, ion-menu.md ion-note {
padding-left: 10px;
}
ion-menu.md ion-list#inbox-list {
border-bottom: 1px solid var(--ion-color-step-150, #d7d8da);
}
ion-menu.md ion-list#inbox-list ion-list-header {
font-size: 22px;
font-weight: 600;
min-height: 20px;
}
ion-menu.md ion-list#labels-list ion-list-header {
font-size: 16px;
margin-bottom: 18px;
color: #757575;
min-height: 26px;
}
ion-menu.md ion-item {
--padding-start: 10px;
--padding-end: 10px;
border-radius: 4px;
}
ion-menu.md ion-item.selected {
--background: rgba(var(--ion-color-primary-rgb), 0.14);
}
ion-menu.md ion-item.selected ion-icon {
color: var(--ion-color-primary);
}
ion-menu.md ion-item ion-icon {
color: #616e7e;
}
ion-menu.md ion-item ion-label {
font-weight: 500;
}
ion-menu.ios ion-content {
--padding-bottom: 20px;
}
ion-menu.ios ion-list {
padding: 20px 0 0 0;
}
ion-menu.ios ion-note {
line-height: 24px;
margin-bottom: 20px;
}
ion-menu.ios ion-item {
--padding-start: 16px;
--padding-end: 16px;
--min-height: 50px;
}
ion-menu.ios ion-item ion-icon {
font-size: 24px;
color: #73849a;
}
ion-menu.ios ion-item .selected ion-icon {
color: var(--ion-color-primary);
}
ion-menu.ios ion-list#labels-list ion-list-header {
margin-bottom: 8px;
}
ion-menu.ios ion-list-header,
ion-menu.ios ion-note {
padding-left: 16px;
padding-right: 16px;
}
ion-menu.ios ion-note {
margin-bottom: 8px;
}
ion-note {
display: inline-block;
font-size: 16px;
color: var(--ion-color-medium-shade);
}
ion-item.selected {
--color: var(--ion-color-primary);
}

View File

@@ -0,0 +1,37 @@
import { IonContent, IonIcon, IonItem, IonLabel, IonList, IonListHeader, IonMenu, IonMenuToggle, IonNote } from '@ionic/react';
import { useLocation } from 'react-router-dom';
import { star, starOutline } from 'ionicons/icons';
import './Menu.css';
const Menu = ({ pages }) => {
const location = useLocation();
return (
<IonMenu contentId="main" type="overlay">
<IonContent>
<IonList id="inbox-list">
<IonListHeader>Overlay Hooks</IonListHeader>
<IonNote>Choose one below to see a demo</IonNote>
{ pages.map((appPage, index) => {
const isSelected = location.pathname === appPage.url;
return (
<IonMenuToggle key={ index } autoHide={false}>
<IonItem className={ isSelected ? 'selected' : '' } routerLink={ appPage.url } routerDirection="none" lines="none" detail={false}>
<IonIcon slot="start" icon={ isSelected ? star : starOutline } />
<IonLabel>{ appPage.label }</IonLabel>
</IonItem>
</IonMenuToggle>
);
})}
</IonList>
</IonContent>
</IonMenu>
);
};
export default Menu;

View File

@@ -0,0 +1,58 @@
import { IonButton, IonButtons, IonContent, IonHeader, IonMenuButton, IonPage, IonTitle, IonToolbar, useIonActionSheet } from '@ionic/react';
const ActionSheet = () => {
const [ present, dismiss ] = useIonActionSheet();
return (
<IonPage>
<IonHeader>
<IonToolbar>
<IonButtons slot="start">
<IonMenuButton />
</IonButtons>
<IonTitle>Action Sheet</IonTitle>
</IonToolbar>
</IonHeader>
<IonContent fullscreen>
<IonHeader collapse="condense">
<IonToolbar>
<IonTitle size="large">Action Sheet</IonTitle>
</IonToolbar>
</IonHeader>
<IonButton
expand="block"
onClick={() =>
present({
buttons: [{ text: 'Ok' }, { text: 'Cancel' }],
header: 'Action Sheet'
})
}
>
Show ActionSheet
</IonButton>
<IonButton
expand="block"
onClick={() =>
present([{ text: 'Ok' }, { text: 'Cancel' }], 'Action Sheet')
}
>
Show ActionSheet using params
</IonButton>
<IonButton
expand="block"
onClick={() => {
present([{ text: 'Ok' }, { text: 'Cancel' }], 'Action Sheet');
setTimeout(dismiss, 3000);
}}
>
Show ActionSheet, hide after 3 seconds
</IonButton>
</IonContent>
</IonPage>
);
};
export default ActionSheet;

View File

@@ -0,0 +1,53 @@
import { IonButton, IonButtons, IonContent, IonHeader, IonMenuButton, IonPage, IonTitle, IonToolbar, useIonAlert } from '@ionic/react';
const Alert = () => {
const [ present ] = useIonAlert();
return (
<IonPage>
<IonHeader>
<IonToolbar>
<IonButtons slot="start">
<IonMenuButton />
</IonButtons>
<IonTitle>Alert</IonTitle>
</IonToolbar>
</IonHeader>
<IonContent fullscreen>
<IonHeader collapse="condense">
<IonToolbar>
<IonTitle size="large">Alert</IonTitle>
</IonToolbar>
</IonHeader>
<IonButton
expand="block"
onClick={() =>
present({
cssClass: 'my-css',
header: 'Alert',
message: 'alert from hook',
buttons: [
'Cancel',
{ text: 'Ok', handler: (d) => console.log('ok pressed') },
],
onDidDismiss: (e) => console.log('did dismiss'),
})
}
>
Show Alert
</IonButton>
<IonButton
expand="block"
onClick={() => present('hello with params', [{ text: 'Ok' }])}
>
Show Alert using params
</IonButton>
</IonContent>
</IonPage>
);
};
export default Alert;

View File

@@ -0,0 +1,54 @@
import { IonButtons, IonCard, IonCardHeader, IonContent, IonHeader, IonMenuButton, IonPage, IonTitle, IonToolbar, IonCardTitle, IonCardSubtitle, IonCardContent, IonText } from '@ionic/react';
const All = () => {
return (
<IonPage>
<IonHeader>
<IonToolbar>
<IonButtons slot="start">
<IonMenuButton />
</IonButtons>
<IonTitle>All</IonTitle>
</IonToolbar>
</IonHeader>
<IonContent fullscreen>
<IonHeader collapse="condense">
<IonToolbar>
<IonTitle size="large">All</IonTitle>
</IonToolbar>
</IonHeader>
<IonCard>
<IonCardHeader>
<IonCardSubtitle>Sample usage</IonCardSubtitle>
<IonCardTitle>Overlay Hooks</IonCardTitle>
</IonCardHeader>
<IonCardContent>
<IonText>
<p>
In Ionic React 5.6, the team packaged up a new set of hooks for controlling overlay components that they thought we might like. What is an overlay you ask? Its the term that Ionic give components that display over your current content, such as alerts, modals, toasts, etc.
</p>
</IonText>
<br />
<IonText>
<p>
All of the code is taken from the Ionic Framework docs. You can find the blog post outlining these new overlay hooks <a href="https://ionicframework.com/blog/introducing-the-new-overlay-hooks-for-ionic-react/" target="_blank" rel="noreferrer">here.</a>
</p>
</IonText>
<br />
<IonText>
<p>
Check out the samples by navigating to a respective one in the side menu.
</p>
</IonText>
</IonCardContent>
</IonCard>
</IonContent>
</IonPage>
);
};
export default All;

View File

@@ -0,0 +1,46 @@
import { IonButton, IonButtons, IonContent, IonHeader, IonMenuButton, IonPage, IonTitle, IonToolbar, useIonLoading } from '@ionic/react';
const Loading = () => {
const [ present ] = useIonLoading();
return (
<IonPage>
<IonHeader>
<IonToolbar>
<IonButtons slot="start">
<IonMenuButton />
</IonButtons>
<IonTitle>Loading</IonTitle>
</IonToolbar>
</IonHeader>
<IonContent fullscreen>
<IonHeader collapse="condense">
<IonToolbar>
<IonTitle size="large">Loading</IonTitle>
</IonToolbar>
</IonHeader>
<IonButton
expand="block"
onClick={() =>
present({
duration: 3000,
})
}
>
Show Loading
</IonButton>
<IonButton
expand="block"
onClick={() => present('Loading', 2000, 'dots')}
>
Show Loading using params
</IonButton>
</IonContent>
</IonPage>
);
};
export default Loading;

View File

@@ -0,0 +1,68 @@
import { IonButton, IonButtons, IonContent, IonHeader, IonMenuButton, IonPage, IonText, IonTitle, IonToolbar, useIonModal } from '@ionic/react';
import { useState } from 'react';
const Modal = () => {
const Body = ({ count, onDismiss, onIncrement }) => (
<div className="ion-text-center">
<IonText color="dark" className="ion-text-center">Count: { count }</IonText>
<IonButton expand="block" onClick={ () => onIncrement() }>
Increment Count
</IonButton>
<IonButton expand="block" onClick={ () => onDismiss() }>
Close
</IonButton>
</div>
);
const [count, setCount] = useState(0);
const handleIncrement = () => {
setCount(count + 1);
};
const handleDismiss = () => {
dismiss();
};
const [present, dismiss] = useIonModal(Body, {
count,
onDismiss: handleDismiss,
onIncrement: handleIncrement,
});
return (
<IonPage>
<IonHeader>
<IonToolbar>
<IonButtons slot="start">
<IonMenuButton />
</IonButtons>
<IonTitle>Modal</IonTitle>
</IonToolbar>
</IonHeader>
<IonContent fullscreen>
<IonHeader collapse="condense">
<IonToolbar>
<IonTitle size="large">Modal</IonTitle>
</IonToolbar>
</IonHeader>
<IonButton
expand="block"
onClick={() => {
present({
cssClass: 'my-class',
});
}}
>
Show Modal
</IonButton>
<div>Count: {count}</div>
</IonContent>
</IonPage>
);
};
export default Modal;

View File

@@ -0,0 +1,97 @@
import { IonButton, IonButtons, IonContent, IonHeader, IonMenuButton, IonPage, IonTitle, IonToolbar, useIonPicker } from '@ionic/react';
import { useState } from 'react';
const Picker = () => {
const [ present ] = useIonPicker();
const [ value, setValue ] = useState('');
return (
<IonPage>
<IonHeader>
<IonToolbar>
<IonButtons slot="start">
<IonMenuButton />
</IonButtons>
<IonTitle>Picker</IonTitle>
</IonToolbar>
</IonHeader>
<IonContent fullscreen>
<IonHeader collapse="condense">
<IonToolbar>
<IonTitle size="large">Picker</IonTitle>
</IonToolbar>
</IonHeader>
<IonButton
expand="block"
onClick={() =>
present({
buttons: [
{
text: 'Confirm',
handler: (selected) => {
setValue(selected.animal.value)
},
},
],
columns: [
{
name: 'animal',
options: [
{ text: 'Dog', value: 'dog' },
{ text: 'Cat', value: 'cat' },
{ text: 'Bird', value: 'bird' },
],
},
],
})
}
>
Show Picker
</IonButton>
<IonButton
expand="block"
onClick={() =>
present(
[
{
name: 'animal',
options: [
{ text: 'Dog', value: 'dog' },
{ text: 'Cat', value: 'cat' },
{ text: 'Bird', value: 'bird' },
],
},
{
name: 'vehicle',
options: [
{ text: 'Car', value: 'car' },
{ text: 'Truck', value: 'truck' },
{ text: 'Bike', value: 'bike' },
],
},
],
[
{
text: 'Confirm',
handler: (selected) => {
setValue(`${selected.animal.value}, ${selected.vehicle.value}`)
},
},
]
)
}
>
Show Picker using params
</IonButton>
{value && (
<div>Selected Value: {value}</div>
)}
</IonContent>
</IonPage>
);
};
export default Picker;

View File

@@ -0,0 +1,53 @@
import { IonButtons, IonContent, IonHeader, IonItem, IonListHeader, IonMenuButton, IonPage, IonTitle, IonToolbar, IonList, useIonPopover, IonButton } from '@ionic/react';
const Popover = () => {
const PopoverList = ({ onHide }) => (
<IonList>
<IonListHeader>Ionic</IonListHeader>
<IonItem button>Learn Ionic</IonItem>
<IonItem button>Documentation</IonItem>
<IonItem button>Showcase</IonItem>
<IonItem button>GitHub Repo</IonItem>
<IonItem lines="none" detail={false} button onClick={ onHide }>
Close
</IonItem>
</IonList>
);
const [ present, dismiss ] = useIonPopover(PopoverList, { onHide: () => dismiss() });
return (
<IonPage>
<IonHeader>
<IonToolbar>
<IonButtons slot="start">
<IonMenuButton />
</IonButtons>
<IonTitle>Popover</IonTitle>
</IonToolbar>
</IonHeader>
<IonContent fullscreen>
<IonHeader collapse="condense">
<IonToolbar>
<IonTitle size="large">Popover</IonTitle>
</IonToolbar>
</IonHeader>
<IonButton
expand="block"
onClick={(e) =>
present({
event: e.nativeEvent,
})
}
>
Show Popover
</IonButton>
</IonContent>
</IonPage>
);
};
export default Popover;

View File

@@ -0,0 +1,52 @@
import { IonButton, IonButtons, IonContent, IonHeader, IonMenuButton, IonPage, IonTitle, IonToolbar, useIonToast } from '@ionic/react';
const Toast = () => {
const [ present, dismiss ] = useIonToast();
return (
<IonPage>
<IonHeader>
<IonToolbar>
<IonButtons slot="start">
<IonMenuButton />
</IonButtons>
<IonTitle>Toast</IonTitle>
</IonToolbar>
</IonHeader>
<IonContent fullscreen>
<IonHeader collapse="condense">
<IonToolbar>
<IonTitle size="large">Toast</IonTitle>
</IonToolbar>
</IonHeader>
<IonButton
expand="block"
onClick={() =>
present({
buttons: [{ text: 'hide', handler: () => dismiss() }],
message: 'toast from hook, click hide to dismiss',
onDidDismiss: () => console.log('dismissed'),
onWillDismiss: () => console.log('will dismiss'),
})
}
>
Show Toast
</IonButton>
<IonButton
expand="block"
onClick={() => present('hello from hook', 3000)}
>
Show Toast using params, closes in 3 secs
</IonButton>
<IonButton expand="block" onClick={dismiss}>
Hide Toast
</IonButton>
</IonContent>
</IonPage>
);
};
export default Toast;

View File

@@ -1,62 +0,0 @@
import { IonCardSubtitle, IonCol, IonIcon, IonNote, IonRow } from '@ionic/react';
import { pulseOutline, sunnyOutline, thermometerOutline } from 'ionicons/icons';
import { useEffect, useState } from 'react';
export const WeatherProperty = ({ type, currentWeather }: { type: any; currentWeather: any }) => {
const [property, setProperty] = useState(false);
const properties = {
wind: {
isIcon: false,
icon: '/assets/WeatherDemo/wind.png',
alt: 'wind',
label: 'Wind',
value: `${currentWeather.current.wind_mph}mph`,
},
feelsLike: {
isIcon: true,
icon: thermometerOutline,
alt: 'feels like',
label: 'Feels like',
value: `${currentWeather.current.feelslike_c}°C`,
},
indexUV: {
isIcon: true,
icon: sunnyOutline,
alt: 'index uv',
label: 'Index UV',
value: currentWeather.current.uv,
},
pressure: {
isIcon: true,
icon: pulseOutline,
alt: 'pressure',
label: 'Pressure',
value: `${currentWeather.current.pressure_mb} mbar`,
},
};
useEffect(() => {
setProperty(properties[type]);
}, [type]);
return (
<IonCol size="6">
<IonRow className="ion-justify-content-center ion-align-items-center">
<IonCol size="3">
{!property.isIcon && (
<img alt={property.alt} src={property.icon} height="32" width="32" />
)}
{property.isIcon && (
<IonIcon icon={property.icon} color="medium" style={{ fontSize: '2rem' }} />
)}
</IonCol>
<IonCol size="9">
<IonCardSubtitle>{property.label}</IonCardSubtitle>
<IonNote>{property.value}</IonNote>
</IonCol>
</IonRow>
</IonCol>
);
};

View File

@@ -1,48 +0,0 @@
import { IonCard, IonCardContent, IonGrid, IonRow, IonText, IonCardTitle } from '@ionic/react';
import { WeatherProperty } from './WeatherProperty';
export const CurrentWeather = ({ currentWeather }: { currentWeather: any }) => (
<IonGrid>
<IonCard>
<IonCardContent className="ion-text-center">
<IonText color="primary">
<h1>
{currentWeather.location.region},{' '}
<span style={{ color: 'gray' }}>{currentWeather.location.country}</span>
</h1>
</IonText>
<div className="ion-margin-top">
<img
alt="condition"
src={currentWeather.current.condition.icon.replace('//', 'https://')}
/>
<IonText color="dark">
<h1 style={{ fontWeight: 'bold' }}>{currentWeather.current.condition.text}</h1>
</IonText>
<IonText color="medium">
<p>{new Date(currentWeather.location.localtime).toDateString()}</p>
</IonText>
</div>
<IonCardTitle style={{ fontSize: '3rem' }} className="ion-margin-top">
{currentWeather.current.temp_c}&#8451;
</IonCardTitle>
<IonGrid className="ion-margin-top">
<IonRow>
<WeatherProperty type="wind" currentWeather={currentWeather} />
<WeatherProperty type="feelsLike" currentWeather={currentWeather} />
</IonRow>
<IonRow className="ion-margin-top">
<WeatherProperty type="indexUV" currentWeather={currentWeather} />
<WeatherProperty type="pressure" currentWeather={currentWeather} />
</IonRow>
</IonGrid>
</IonCardContent>
</IonCard>
</IonGrid>
);

View File

@@ -1,117 +0,0 @@
import {
IonCard,
IonCardContent,
IonCardSubtitle,
IonCardTitle,
IonCol,
IonGrid,
IonIcon,
IonNote,
IonRow,
IonSkeletonText,
IonText,
IonThumbnail,
} from '@ionic/react';
import { pulseOutline, sunnyOutline, thermometerOutline } from 'ionicons/icons';
export const SkeletonDashboard = () => (
<IonGrid>
<IonCard>
<IonCardContent className="ion-text-center">
<IonText color="primary">
<h1>
<IonSkeletonText animated style={{ height: '2rem', width: '90%' }} />
</h1>
</IonText>
<div className="ion-margin-top">
<IonThumbnail>
<IonSkeletonText animated style={{ width: '2rem', height: '2rem' }} />
</IonThumbnail>
<IonText color="dark">
<h1 style={{ fontWeight: 'bold' }}>
<IonSkeletonText animated style={{ height: '2rem', width: '90%' }} />
</h1>
</IonText>
<IonText color="medium">
<p>
<IonSkeletonText animated style={{ height: '2rem', width: '90%' }} />
</p>
</IonText>
</div>
<IonCardTitle style={{ fontSize: '3rem' }} className="ion-margin-top">
<IonSkeletonText animated style={{ height: '3rem', width: '30%', textAlign: 'center' }} />
</IonCardTitle>
<IonGrid className="ion-margin-top">
<IonRow>
<IonCol size="6">
<IonRow className="ion-justify-content-center ion-align-items-center">
<IonCol size="3">
<img alt="wind" src="/assets/WeatherDemo/wind.png" height="32" width="32" />
</IonCol>
<IonCol size="9">
<IonCardSubtitle>Wind</IonCardSubtitle>
<IonNote>
<IonSkeletonText animated style={{ height: '2rem', width: '90%' }} />
</IonNote>
</IonCol>
</IonRow>
</IonCol>
<IonCol size="6">
<IonRow className="ion-justify-content-center ion-align-items-center">
<IonCol size="3">
<IonIcon icon={thermometerOutline} color="medium" style={{ fontSize: '2rem' }} />
</IonCol>
<IonCol size="9">
<IonCardSubtitle>Feels like</IonCardSubtitle>
<IonNote>
<IonSkeletonText animated style={{ height: '2rem', width: '90%' }} />
</IonNote>
</IonCol>
</IonRow>
</IonCol>
</IonRow>
<IonRow className="ion-margin-top">
<IonCol size="6">
<IonRow className="ion-justify-content-center ion-align-items-center">
<IonCol size="3">
<IonIcon icon={sunnyOutline} color="medium" style={{ fontSize: '2rem' }} />
</IonCol>
<IonCol size="9">
<IonCardSubtitle>Index UV</IonCardSubtitle>
<IonNote>
<IonSkeletonText animated style={{ height: '2rem', width: '90%' }} />
</IonNote>
</IonCol>
</IonRow>
</IonCol>
<IonCol size="6">
<IonRow className="ion-justify-content-center ion-align-items-center">
<IonCol size="3">
<IonIcon icon={pulseOutline} color="medium" style={{ fontSize: '2rem' }} />
</IonCol>
<IonCol size="9">
<IonCardSubtitle>Pressure</IonCardSubtitle>
<IonNote>
<IonSkeletonText animated style={{ height: '2rem', width: '90%' }} />
</IonNote>
</IonCol>
</IonRow>
</IonCol>
</IonRow>
</IonGrid>
</IonCardContent>
</IonCard>
</IonGrid>
);

View File

@@ -1,62 +0,0 @@
import { IonCardSubtitle, IonCol, IonIcon, IonNote, IonRow } from '@ionic/react';
import { pulseOutline, sunnyOutline, thermometerOutline } from 'ionicons/icons';
import { useEffect, useState } from 'react';
export const WeatherProperty = ({ type, currentWeather }: { type: any; currentWeather: any }) => {
const [property, setProperty] = useState(false);
const properties = {
wind: {
isIcon: false,
icon: '/assets/WeatherDemo/wind.png',
alt: 'wind',
label: 'Wind',
value: `${currentWeather.current.wind_mph}mph`,
},
feelsLike: {
isIcon: true,
icon: thermometerOutline,
alt: 'feels like',
label: 'Feels like',
value: `${currentWeather.current.feelslike_c}°C`,
},
indexUV: {
isIcon: true,
icon: sunnyOutline,
alt: 'index uv',
label: 'Index UV',
value: currentWeather.current.uv,
},
pressure: {
isIcon: true,
icon: pulseOutline,
alt: 'pressure',
label: 'Pressure',
value: `${currentWeather.current.pressure_mb} mbar`,
},
};
useEffect(() => {
setProperty(properties[type]);
}, [type]);
return (
<IonCol size="6">
<IonRow className="ion-justify-content-center ion-align-items-center">
<IonCol size="3">
{!property.isIcon && (
<img alt={property.alt} src={property.icon} height="32" width="32" />
)}
{property.isIcon && (
<IonIcon icon={property.icon} color="medium" style={{ fontSize: '2rem' }} />
)}
</IonCol>
<IonCol size="9">
<IonCardSubtitle>{property.label}</IonCardSubtitle>
<IonNote>{property.value}</IonNote>
</IonCol>
</IonRow>
</IonCol>
);
};

View File

@@ -1,48 +0,0 @@
import { IonCard, IonCardContent, IonGrid, IonRow, IonText, IonCardTitle } from '@ionic/react';
import { WeatherProperty } from './WeatherProperty';
export const CurrentWeather = ({ currentWeather }: { currentWeather: any }) => (
<IonGrid>
<IonCard>
<IonCardContent className="ion-text-center">
<IonText color="primary">
<h1>
{currentWeather.location.region},{' '}
<span style={{ color: 'gray' }}>{currentWeather.location.country}</span>
</h1>
</IonText>
<div className="ion-margin-top">
<img
alt="condition"
src={currentWeather.current.condition.icon.replace('//', 'https://')}
/>
<IonText color="dark">
<h1 style={{ fontWeight: 'bold' }}>{currentWeather.current.condition.text}</h1>
</IonText>
<IonText color="medium">
<p>{new Date(currentWeather.location.localtime).toDateString()}</p>
</IonText>
</div>
<IonCardTitle style={{ fontSize: '3rem' }} className="ion-margin-top">
{currentWeather.current.temp_c}&#8451;
</IonCardTitle>
<IonGrid className="ion-margin-top">
<IonRow>
<WeatherProperty type="wind" currentWeather={currentWeather} />
<WeatherProperty type="feelsLike" currentWeather={currentWeather} />
</IonRow>
<IonRow className="ion-margin-top">
<WeatherProperty type="indexUV" currentWeather={currentWeather} />
<WeatherProperty type="pressure" currentWeather={currentWeather} />
</IonRow>
</IonGrid>
</IonCardContent>
</IonCard>
</IonGrid>
);

View File

@@ -1,27 +0,0 @@
import { IonFab, IonFabButton, IonFabList, IonIcon } from '@ionic/react';
import { addOutline, cameraOutline, qrCodeOutline } from 'ionicons/icons';
export const CustomFab = ({ start }) => {
return (
<IonFab
vertical="bottom"
horizontal="end"
slot="fixed"
className="ion-padding-bottom ion-padding-end"
>
<IonFabButton>
<IonIcon icon={qrCodeOutline} />
</IonFabButton>
<IonFabList side="top" className="ion-padding-bottom">
<IonFabButton color="primary" onClick={start}>
<IonIcon icon={cameraOutline} />
</IonFabButton>
<IonFabButton color="primary" routerLink="/demo-qr-scanner/manual">
<IonIcon icon={addOutline} />
</IonFabButton>
</IonFabList>
</IonFab>
);
};

View File

@@ -1,15 +0,0 @@
import { IonCol, IonRow, IonText } from '@ionic/react';
export const NoQRCodes = () => (
<IonRow className="ion-text-center ion-justify-content-center">
<IonCol size="9">
<h3>It looks like you don't have any QR codes stored.</h3>
<img src="/assets/icon2.png" alt="icon" />
<p>
Click the <IonText color="primary">button</IonText> in the bottom right to scan a code or
generate a code.
</p>
</IonCol>
</IonRow>
);

View File

@@ -1,106 +0,0 @@
import {
IonButton,
IonButtons,
IonCard,
IonCardContent,
IonCardHeader,
IonCardTitle,
IonCol,
IonContent,
IonGrid,
IonHeader,
IonIcon,
IonNote,
IonPage,
IonRow,
IonTitle,
IonToolbar,
useIonToast,
} from '@ionic/react';
import QRCode from 'react-qr-code';
import { addQRCode } from '../store/QRStore';
import useSound from 'use-sound';
import closeSound from '../sounds/close.wav';
import { reloadOutline } from 'ionicons/icons';
export const QRCodeScannedModal = ({ dismiss, code, set, scan }) => {
const [play] = useSound(closeSound);
const [showToast] = useIonToast();
const handleDismiss = () => {
dismiss();
play();
};
const handleScanAgain = () => {
handleDismiss();
setTimeout(() => {
scan();
}, 10);
};
const handleAdd = async () => {
addQRCode(code.text ? code.text : code, true);
showToast({
header: 'Success!',
message: 'QR Code stored successfully.',
duration: 3000,
color: 'primary',
});
handleDismiss();
};
return (
<IonPage>
<IonHeader>
<IonToolbar>
<IonTitle>View QR Code</IonTitle>
<IonButtons slot="end">
<IonButton onClick={handleDismiss}>Close</IonButton>
</IonButtons>
</IonToolbar>
</IonHeader>
<IonContent>
<IonGrid className="ion-padding-top ion-margin-top">
<IonRow className="ion-justify-content-center ion-text-center animate__animated animate__lightSpeedInLeft animate__faster">
<IonCol size="12">
<QRCode value={code.text ? code.text : code} />
</IonCol>
</IonRow>
<IonRow>
<IonCol size="12">
<IonCard>
<IonCardHeader>
<IonCardTitle>QR Code data</IonCardTitle>
<IonNote>This is what the code represents</IonNote>
</IonCardHeader>
<IonCardContent>
<p>{code.text ? code.text : code}</p>
</IonCardContent>
</IonCard>
</IonCol>
</IonRow>
<IonRow>
<IonCol size="6">
<IonButton expand="block" fill="outline" onClick={handleScanAgain}>
<IonIcon icon={reloadOutline} />
&nbsp; Scan again
</IonButton>
</IonCol>
<IonCol size="6">
<IonButton expand="block" onClick={handleAdd}>
Store &rarr;
</IonButton>
</IonCol>
</IonRow>
</IonGrid>
</IonContent>
</IonPage>
);
};

View File

@@ -1,45 +0,0 @@
import {
IonButton,
IonButtons,
IonCol,
IonContent,
IonGrid,
IonHeader,
IonPage,
IonRow,
IonTitle,
IonToolbar,
} from '@ionic/react';
// import QrReader from "react-qr-reader";
export const QRWebModal = ({ dismiss, set, scan, error }) => {
return (
<IonPage>
<IonHeader>
<IonToolbar>
<IonTitle>Scan QR Code</IonTitle>
<IonButtons slot="end">
<IonButton onClick={dismiss}>Close</IonButton>
</IonButtons>
</IonToolbar>
</IonHeader>
<IonContent>
<IonGrid className="ion-padding-top ion-margin-top">
<IonRow className="ion-justify-content-center ion-text-center animate__animated animate__lightSpeedInLeft animate__faster">
<IonCol size="12">
{/*
<QrReader
delay={ 500 }
onError={ error }
onScan={ scan }
style={{ width: "100%", height: "100%" }}
/>
*/}
</IonCol>
</IonRow>
</IonGrid>
</IonContent>
</IonPage>
);
};

View File

@@ -1,117 +0,0 @@
import {
IonCard,
IonCardContent,
IonCardSubtitle,
IonCardTitle,
IonCol,
IonGrid,
IonIcon,
IonNote,
IonRow,
IonSkeletonText,
IonText,
IonThumbnail,
} from '@ionic/react';
import { pulseOutline, sunnyOutline, thermometerOutline } from 'ionicons/icons';
export const SkeletonDashboard = () => (
<IonGrid>
<IonCard>
<IonCardContent className="ion-text-center">
<IonText color="primary">
<h1>
<IonSkeletonText animated style={{ height: '2rem', width: '90%' }} />
</h1>
</IonText>
<div className="ion-margin-top">
<IonThumbnail>
<IonSkeletonText animated style={{ width: '2rem', height: '2rem' }} />
</IonThumbnail>
<IonText color="dark">
<h1 style={{ fontWeight: 'bold' }}>
<IonSkeletonText animated style={{ height: '2rem', width: '90%' }} />
</h1>
</IonText>
<IonText color="medium">
<p>
<IonSkeletonText animated style={{ height: '2rem', width: '90%' }} />
</p>
</IonText>
</div>
<IonCardTitle style={{ fontSize: '3rem' }} className="ion-margin-top">
<IonSkeletonText animated style={{ height: '3rem', width: '30%', textAlign: 'center' }} />
</IonCardTitle>
<IonGrid className="ion-margin-top">
<IonRow>
<IonCol size="6">
<IonRow className="ion-justify-content-center ion-align-items-center">
<IonCol size="3">
<img alt="wind" src="/assets/WeatherDemo/wind.png" height="32" width="32" />
</IonCol>
<IonCol size="9">
<IonCardSubtitle>Wind</IonCardSubtitle>
<IonNote>
<IonSkeletonText animated style={{ height: '2rem', width: '90%' }} />
</IonNote>
</IonCol>
</IonRow>
</IonCol>
<IonCol size="6">
<IonRow className="ion-justify-content-center ion-align-items-center">
<IonCol size="3">
<IonIcon icon={thermometerOutline} color="medium" style={{ fontSize: '2rem' }} />
</IonCol>
<IonCol size="9">
<IonCardSubtitle>Feels like</IonCardSubtitle>
<IonNote>
<IonSkeletonText animated style={{ height: '2rem', width: '90%' }} />
</IonNote>
</IonCol>
</IonRow>
</IonCol>
</IonRow>
<IonRow className="ion-margin-top">
<IonCol size="6">
<IonRow className="ion-justify-content-center ion-align-items-center">
<IonCol size="3">
<IonIcon icon={sunnyOutline} color="medium" style={{ fontSize: '2rem' }} />
</IonCol>
<IonCol size="9">
<IonCardSubtitle>Index UV</IonCardSubtitle>
<IonNote>
<IonSkeletonText animated style={{ height: '2rem', width: '90%' }} />
</IonNote>
</IonCol>
</IonRow>
</IonCol>
<IonCol size="6">
<IonRow className="ion-justify-content-center ion-align-items-center">
<IonCol size="3">
<IonIcon icon={pulseOutline} color="medium" style={{ fontSize: '2rem' }} />
</IonCol>
<IonCol size="9">
<IonCardSubtitle>Pressure</IonCardSubtitle>
<IonNote>
<IonSkeletonText animated style={{ height: '2rem', width: '90%' }} />
</IonNote>
</IonCol>
</IonRow>
</IonCol>
</IonRow>
</IonGrid>
</IonCardContent>
</IonCard>
</IonGrid>
);

View File

@@ -1,32 +0,0 @@
import { IonIcon, IonLabel, IonRouterOutlet, IonTabBar, IonTabButton, 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 './style.scss';
function DemoWeatherAppUi() {
return (
<IonTabs>
<IonRouterOutlet>
<Route exact path="/demo-react-qr-code/home">
<Tab1 />
</Route>
<Route exact path="/demo-react-qr-code/manual">
<Tab2 />
</Route>
<Route exact path="/demo-react-qr-code/camera">
<Tab3 />
</Route>
<Redirect exact path="/demo-react-qr-code" to="/demo-react-qr-code/home" />
</IonRouterOutlet>
</IonTabs>
);
}
export default DemoWeatherAppUi;

View File

@@ -1,114 +0,0 @@
import { BarcodeScanner } from '@ionic-native/barcode-scanner';
import { IonContent, IonGrid, IonHeader, IonPage, IonTitle, IonToolbar, useIonModal, getPlatforms } from '@ionic/react';
import { useStoreState } from 'pullstate';
import { useState } from 'react';
import { useRef } from 'react';
import useSound from 'use-sound';
import { CustomFab } from '../components/CustomFab';
import { NoQRCodes } from '../components/NoQRCodes';
import { QRCodeList } from '../components/QRCodeList';
import { QRCodeScannedModal } from '../components/QRCodeScannedModal';
import { QRStore } from '../store';
import { getCodes } from '../store/Selectors';
import './Tab1.css';
import openSound from "../sounds/open.wav";
import { QRWebModal } from '../components/QRWebModal';
const Tab1 = () => {
const pageRef = useRef();
const codes = useStoreState(QRStore, getCodes);
const [ play ] = useSound(openSound);
const [ QRData, setQRData ] = useState(false);
const handleScan = data => {
if (data) {
setQRData(data);
play();
handleSuccess(data);
}
}
const handleError = err => {
console.error(err)
}
const start = async () => {
const platforms = getPlatforms();
const isWeb = (platforms.includes("desktop") || platforms.includes("mobileweb") || platforms.includes("pwa"));
if (!isWeb) {
const data = await BarcodeScanner.scan();
if (data) {
handleSuccess(data);
}
} else {
presentWebModal({
presentingElement: pageRef.current
});
}
}
const handleSuccess = data => {
setQRData(data);
console.log(data);
dismissWebModal();
play();
present({
presentingElement: pageRef.current
});
}
const [ present, dismiss ] = useIonModal(QRCodeScannedModal, {
dismiss: () => dismiss(),
code: QRData,
set: () => setQRData(),
scan: () => start()
});
const [ presentWebModal, dismissWebModal ] = useIonModal(QRWebModal, {
dismiss: () => dismissWebModal(),
set: () => setQRData(),
scan: handleScan,
error: handleError
});
return (
<IonPage ref={ pageRef }>
<IonHeader>
<IonToolbar>
<IonTitle>QR Codes</IonTitle>
</IonToolbar>
</IonHeader>
<IonContent fullscreen>
<IonHeader collapse="condense">
<IonToolbar>
<IonTitle size="large">QR Codes</IonTitle>
</IonToolbar>
</IonHeader>
<IonGrid>
{ codes.length < 1 && <NoQRCodes /> }
{ codes.length > 0 && <QRCodeList codes={ codes } pageRef={ pageRef } /> }
</IonGrid>
<CustomFab start={ start } />
</IonContent>
</IonPage>
);
};
export default Tab1;

View File

@@ -1,105 +0,0 @@
import { IonBackButton, IonButton, IonButtons, IonCol, IonContent, IonGrid, IonHeader, IonInput, IonItem, IonLabel, IonNote, IonPage, IonRow, IonTextarea, IonTitle, IonToolbar, useIonToast } from '@ionic/react';
import './Tab2.css';
import QRCode from "react-qr-code";
import { useState } from 'react';
import { addQRCode } from '../store/QRStore';
const Tab2 = () => {
const [ data, setData ] = useState("");
const [ showToast ] = useIonToast();
const handleAdd = async () => {
if (data === "") {
showToast({
header: "Error!",
message: "Please enter some data to store.",
duration: 3000,
color: "danger"
});
} else {
addQRCode(data);
showToast({
header: "Success!",
message: "QR Code stored successfully.",
duration: 3000,
color: "primary"
});
setData("");
}
}
return (
<IonPage>
<IonHeader>
<IonToolbar>
<IonButtons slot="start">
<IonBackButton text="QR Codes" />
</IonButtons>
<IonTitle>Generate QR Code</IonTitle>
</IonToolbar>
</IonHeader>
<IonContent fullscreen>
<IonHeader collapse="condense">
<IonToolbar>
<IonTitle size="large">Generate QR Code</IonTitle>
</IonToolbar>
</IonHeader>
<IonGrid>
<IonRow>
<IonCol size="12">
<IonItem lines="none">
<IonLabel className="ion-text-wrap">
<h1>You can generate a QR code to store or share with friends.</h1>
<p>You'll see a live preview of the QR Code</p>
</IonLabel>
</IonItem>
</IonCol>
</IonRow>
<IonRow>
<IonCol size="12">
<IonItem>
<IonLabel position="stacked">Data to store</IonLabel>
<IonTextarea rows="3" placeholder="Enter a URL or secret information" type="text" inputmode="text" value={ data } onIonChange={ e => setData(e.target.value) } />
</IonItem>
</IonCol>
</IonRow>
<IonRow className="ion-text-center ion-margin-top">
<IonCol size="12">
{ data !== "" ? <QRCode value={ data } /> : <img src="/assets/placeholder2.png" alt="placeholder qr" height="256" /> }
</IonCol>
</IonRow>
<IonRow className="ion-text-center ion-justify-content-center">
<IonCol size="10">
<IonItem lines="none">
<IonLabel className="ion-text-wrap ion-text-center">
<p>When you're ready, you can store the generated QR Code</p>
</IonLabel>
</IonItem>
</IonCol>
</IonRow>
<IonRow>
<IonCol size="12">
<IonButton expand="block" onClick={ handleAdd }>Store &rarr;</IonButton>
</IonCol>
</IonRow>
</IonGrid>
</IonContent>
</IonPage>
);
};
export default Tab2;

View File

@@ -1,102 +0,0 @@
import { IonBackButton, IonButton, IonButtons, IonCard, IonCardContent, IonCardHeader, IonCardTitle, IonCol, IonContent, IonGrid, IonHeader, IonIcon, IonNote, IonPage, IonRow, IonTitle, IonToolbar, useIonToast } from '@ionic/react';
import './Tab3.css';
import { useState } from 'react';
import { BarcodeScanner } from "@ionic-native/barcode-scanner";
import QRCode from 'react-qr-code';
import { addQRCode } from '../store/QRStore';
import { reloadOutline } from 'ionicons/icons';
const Tab3 = () => {
const [ QRData, setQRData ] = useState(false);
const start = async () => {
const data = await BarcodeScanner.scan();
setQRData(data);
}
const [ showToast ] = useIonToast();
const handleAdd = async () => {
addQRCode(QRData.text, true);
showToast({
header: "Success!",
message: "QR Code stored successfully.",
duration: 3000,
color: "primary"
});
setQRData(false);
}
return (
<IonPage>
<IonHeader>
<IonToolbar>
<IonButtons slot="start">
<IonBackButton text="QR Codes" />
</IonButtons>
<IonTitle>Scan QR Code</IonTitle>
</IonToolbar>
</IonHeader>
<IonContent fullscreen>
<IonHeader collapse="condense">
<IonToolbar>
<IonTitle size="large">Scan QR Code</IonTitle>
</IonToolbar>
</IonHeader>
<IonGrid>
{ !QRData &&
<IonRow>
<IonCol size="12">
<IonButton expand="block" onClick={ start }>Scan &rarr;</IonButton>
</IonCol>
</IonRow>
}
{ QRData &&
<>
<IonRow className="ion-justify-content-center ion-text-center animate__animated animate__lightSpeedInLeft animate__faster">
<IonCol size="12">
<QRCode value={ QRData.text } />
</IonCol>
</IonRow>
<IonRow>
<IonCol size="12">
<IonCard>
<IonCardHeader>
<IonCardTitle>QR Code data</IonCardTitle>
<IonNote>This is what the code represents</IonNote>
</IonCardHeader>
<IonCardContent>
<p>{ QRData.text }</p>
</IonCardContent>
</IonCard>
</IonCol>
</IonRow>
<IonRow>
<IonCol size="6">
<IonButton expand="block" fill="outline" onClick={ start }>
<IonIcon icon={ reloadOutline } />&nbsp;
Scan again</IonButton>
</IonCol>
<IonCol size="6">
<IonButton expand="block" onClick={ handleAdd }>Store &rarr;</IonButton>
</IonCol>
</IonRow>
</>
}
</IonGrid>
</IonContent>
</IonPage>
);
};
export default Tab3;

View File

@@ -1,19 +0,0 @@
import { Store } from 'pullstate';
const QRStore = new Store({
codes: [],
});
export default QRStore;
export const addQRCode = (data, scanned = false) => {
QRStore.update((s) => {
s.codes = [...s.codes, { id: new Date(), data, scanned }];
});
};
export const removeQRCode = (id) => {
QRStore.update((s) => {
s.codes = s.codes.filter((code) => code.id !== id);
});
};

Some files were not shown because too many files have changed in this diff Show More