Compare commits

...

16 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
louiscklaw
bc731ea2b8 update demo-react-notes, 2025-06-08 19:07:48 +08:00
283 changed files with 7840 additions and 7003 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,24 @@
.container {
text-align: center;
position: absolute;
left: 0;
right: 0;
top: 50%;
transform: translateY(-50%);
}
.container strong {
font-size: 20px;
line-height: 26px;
}
.container p {
font-size: 16px;
line-height: 22px;
color: #8c8c8c;
margin: 0;
}
.container a {
text-decoration: none;
}

View File

@@ -0,0 +1,21 @@
import './ExploreContainer.css';
const ExploreContainer = (): React.JSX.Element => {
return (
<div className="container">
<strong>Ready to create an app?</strong>
<p>
Start with Ionic{' '}
<a
target="_blank"
rel="noopener noreferrer"
href="https://ionicframework.com/docs/components"
>
UI Components
</a>
</p>
</div>
);
};
export default ExploreContainer;

View File

@@ -1,38 +1,27 @@
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 Add from './pages/Add';
function DemoReactNotes() {
return (
<IonTabs>
<IonTabs className="demo-react-notes">
<IonRouterOutlet>
<Route exact path="/demo-react-notes/tab1">
<Tab1 />
<Route exact path="/demo-react-notes/home">
<Home />
</Route>
<Route exact path="/demo-react-notes/tab2">
<Tab2 />
<Route exact path="/demo-react-notes/add">
<Add />
</Route>
<Redirect exact path="/demo-react-notes" to="/demo-react-notes/tab1" />
<Redirect exact path="/demo-react-notes" to="/demo-react-notes/home" />
</IonRouterOutlet>
{/* */}
<IonTabBar slot="bottom">
<IonTabButton tab="tab1" href="/demo-react-notes/tab1">
<IonIcon icon={cloudOutline} />
<IonLabel>Dashboard</IonLabel>
</IonTabButton>
<IonTabButton tab="tab2" href="/demo-react-notes/tab2">
<IonIcon icon={searchOutline} />
<IonLabel>Search</IonLabel>
</IonTabButton>
</IonTabBar>
</IonTabs>
);
}

View File

@@ -0,0 +1,29 @@
.title {
margin-top: 0.35rem;
}
.customInput {
border-radius: 22px !important;
--padding-bottom: 1rem;
--padding-top: 1rem;
box-shadow: 0 0.7px 0.9px rgba(0, 0, 0, 0.101),
0 0.9px 2.5px rgba(0, 0, 0, 0.145),
0 2.5px 6px rgba(0, 0, 0, 0.189),
0 8px 20px rgba(0, 0, 0, 0.29);
}
.customInput {
margin-bottom: 1rem !important;
}
.saveButton {
--border-radius: 12px !important;
--padding-top: 1.75rem !important;
--padding-bottom: 1.75rem !important;
}

View File

@@ -0,0 +1,115 @@
import {
IonBackButton,
IonButton,
IonButtons,
IonCol,
IonContent,
IonGrid,
IonHeader,
IonIcon,
IonItem,
IonLabel,
IonPage,
IonRow,
IonSelect,
IonSelectOption,
IonTextarea,
IonTitle,
IonToolbar,
useIonRouter,
} from '@ionic/react';
import styles from './Add.module.scss';
import { checkmarkOutline } from 'ionicons/icons';
import { getCategories, getNotes } from '../store/Selectors';
import { CategoryStore, NoteStore } from '../store';
import { addNote } from '../store/NoteStore';
import { useState } from 'react';
const Add = (): React.JSX.Element => {
const categories = CategoryStore.useState(getCategories);
const notes = NoteStore.useState(getNotes);
const [noteCategory, setNoteCategory] = useState<number | false>(false);
const [noteContent, setNoteContent] = useState<string>('');
const router = useIonRouter();
const add = () => {
const note = {
id: notes.length + 1,
category_id: noteCategory,
note: noteContent,
complete: false,
};
addNote(note);
router.goBack();
};
return (
<IonPage>
<IonHeader>
<IonToolbar>
<IonButtons slot="start">
<IonBackButton />
</IonButtons>
<IonTitle className={styles.title}>Add note</IonTitle>
</IonToolbar>
</IonHeader>
<IonContent fullscreen>
<IonGrid className="ion-padding-top">
<IonRow>
<IonCol size="12" className="ion-padding-start">
<h1 className={styles.mainTitle}>Add a note</h1>
</IonCol>
</IonRow>
<IonRow>
<IonCol size="12">
<IonItem lines="none" className={styles.customInput}>
<IonLabel position="floating">Category</IonLabel>
<IonSelect
placeholder="Select..."
value={noteCategory}
onIonChange={(e) => setNoteCategory(e.target.value)}
>
{categories.map((category) => {
return (
<IonSelectOption value={category.id} key={category.id}>
{category.name}
</IonSelectOption>
);
})}
</IonSelect>
</IonItem>
</IonCol>
</IonRow>
<IonRow>
<IonCol size="12">
<IonItem lines="none" className={styles.customInput}>
<IonLabel position="floating">Note</IonLabel>
<IonTextarea
value={noteContent}
onIonChange={(e) => setNoteContent(e.target.value)}
placeholder="Enter note text here..."
/>
</IonItem>
</IonCol>
</IonRow>
<IonRow>
<IonCol size="12">
<IonButton expand="block" className={styles.saveButton} onClick={add}>
<IonIcon icon={checkmarkOutline} />
Save note
</IonButton>
</IonCol>
</IonRow>
</IonGrid>
</IonContent>
</IonPage>
);
};
export default Add;

View File

@@ -0,0 +1,130 @@
.heading {
color: var(--lighter-blue-color);
font-size: 1rem;
}
.mainTitle {
font-size: 2rem;
font-weight: 700;
}
.slideHeader {
margin: 0 !important;
padding: 0;
padding: 1.5rem !important;
padding-top: 0 !important;
}
.slideCount {
margin: 0 !important;
padding: 0 !important;
padding-left: 1.5rem !important;
padding-top: 1rem !important;
}
.slideCount h6 {
color: var(--light-blue-color);
}
.slideHeader h4 {
color: white;
margin: 0 !important;
padding: 0 !important;
text-align: left;
font-size: 1.75rem;
}
.categorySlider {
margin-top: -1.6rem;
ion-slide {
width: 60%;
margin-right: 30px;
}
ion-col {
padding-left: 0;
ion-card {
width: 100%;
border-radius: 22px;
// box-shadow: 0px 4px 12px 2px rgba(0, 0, 0, 0.16);
box-shadow: 0 0.7px 0.9px rgba(0, 0, 0, 0.101),
0 1.9px 2.5px rgba(0, 0, 0, 0.145),
0 4.5px 6px rgba(0, 0, 0, 0.189),
0 15px 20px rgba(0, 0, 0, 0.29);
ion-card-header {
text-align: left !important;
}
ion-card-content {
padding: 0;
padding: 0.5rem;
}
}
}
.lastUsed {
display: flex;
flex-direction: row;
align-content: flex-start;
align-items: center;
justify-content: center;
font-size: 0.9rem;
color: white;
}
.categoryColor {
border-bottom: 3px solid var(--pink-color);
margin-left: 1rem;
margin-right: 1rem;
margin-bottom: 0.5rem;
margin-top: -1rem;
}
}
.recentNotes {
padding-left: 0.5rem;
padding-right: 0.5rem;
max-height: 18.8rem;
overflow: scroll;
ion-item {
--padding-start: 2rem;
--padding-end: 2rem;
--border-style: none;
--border-radius: 22px;
--min-height: 4rem;
h4 {
padding-left: 1rem;
margin-top: 0.6rem;
font-size: 1.2rem;
font-weight: 400;
}
}
}
.bottomContainer {
margin-top: -1rem;
}

View File

@@ -0,0 +1,166 @@
import {
IonButton,
IonButtons,
IonCard,
IonCardContent,
IonCardHeader,
IonCardSubtitle,
IonCheckbox,
IonCol,
IonContent,
IonFab,
IonFabButton,
IonGrid,
IonHeader,
IonIcon,
IonItem,
IonPage,
IonRow,
// IonSlide,
// IonSlides,
IonToolbar,
} from '@ionic/react';
import styles from './Home.module.scss';
import { addOutline, menuOutline, notificationsOutline, searchOutline } from 'ionicons/icons';
import { getCategories, getNotes } from '../store/Selectors';
import { CategoryStore, NoteStore } from '../store';
import { markNote } from '../store/NoteStore';
const Home = (): React.JSX.Element => {
return <>TODO: need update IonSlide</>;
const categories = CategoryStore.useState(getCategories);
const notes = NoteStore.useState(getNotes);
const getNoteStyle = (categoryID, isComplete = false) => {
const categoryColor = categories.filter((category) => category.id === categoryID)[0].color;
return {
'--background': categoryColor,
'--background-checked': categoryColor,
'--border-style': 'none',
opacity: isComplete ? '0.6' : '1',
};
};
return (
<IonPage>
<IonHeader>
<IonToolbar>
<IonButtons slot="start">
<IonButton>
<IonIcon icon={menuOutline} />
</IonButton>
</IonButtons>
<IonButtons slot="end">
<IonButton>
<IonIcon icon={searchOutline} />
</IonButton>
<IonButton>
<IonIcon icon={notificationsOutline} />
</IonButton>
</IonButtons>
</IonToolbar>
</IonHeader>
<IonContent fullscreen>
<IonGrid>
<IonRow>
<IonCol size="12" className="ion-padding-start">
<h1 className={styles.mainTitle}>Hello, Alan!</h1>
</IonCol>
</IonRow>
<IonRow>
<IonCol size="12" className="ion-padding-start ion-padding-top">
<IonCardSubtitle className={styles.heading}>Categories</IonCardSubtitle>
</IonCol>
</IonRow>
</IonGrid>
<IonSlides
id="slider"
options={{ slidesPerView: 'auto', zoom: true, grabCursor: true }}
className={`${styles.categorySlider} ion-padding-bottom`}
>
{categories.map((category, index) => {
const noteCount = notes.filter((n) => n.category_id === category.id).length;
return (
<IonSlide key={`categorySlide_${index}`}>
<IonCol className="ion-text-left">
<IonCard>
<IonCardHeader className="ion-no-padding">
<div className={styles.slideCount}>
<h6>
{noteCount} {noteCount === 1 ? 'note' : 'notes'}{' '}
</h6>
</div>
<div className={styles.slideHeader}>
<h4>{category.name}</h4>
</div>
</IonCardHeader>
<IonCardContent>
<div
className={styles.categoryColor}
style={{ borderBottom: `2px solid ${category.color}` }}
></div>
</IonCardContent>
</IonCard>
</IonCol>
</IonSlide>
);
})}
</IonSlides>
<IonGrid className={styles.bottomContainer}>
<IonRow>
<IonCol size="12" className="ion-padding-start">
<IonCardSubtitle className={styles.heading}>Recent Notes</IonCardSubtitle>
</IonCol>
</IonRow>
<div className={styles.recentNotes}>
{notes.map((note, index) => {
return (
<IonRow
key={`note_${index}`}
className="animate__animated animate__faster"
id={`noteRow_${note.id}`}
>
<IonCol size="12">
<IonItem>
<IonCheckbox
checked={note.complete}
style={getNoteStyle(note.category_id, note.complete)}
onClick={() => markNote(note.id)}
/>
<h4
style={
note.complete ? { textDecoration: 'line-through', opacity: '0.6' } : {}
}
>
{note.note}
</h4>
</IonItem>
</IonCol>
</IonRow>
);
})}
</div>
</IonGrid>
<IonFab vertical="bottom" horizontal="end" slot="fixed" className="ion-padding">
<IonFabButton routerLink="/add">
<IonIcon icon={addOutline} />
</IonFabButton>
</IonFab>
</IonContent>
</IonPage>
);
};
export default Home;

View File

@@ -0,0 +1,33 @@
import { Store } from 'pullstate';
interface Category {
id: number;
name: string;
count: string;
color: string;
}
const CategoryStore = new Store({
categories: [
{
id: 1,
name: 'Business',
count: '34',
color: '#60b660',
},
{
id: 2,
name: 'Personal',
count: '12',
color: '#1D68DF',
},
{
id: 3,
name: 'Leisure',
count: '23',
color: '#EB06FF',
},
] as Category[],
});
export default CategoryStore;

View File

@@ -0,0 +1,58 @@
import { Store } from 'pullstate';
interface Note {
id: number;
category_id: number;
note: string;
complete: boolean;
}
const NoteStore = new Store({
notes: [
{
id: 1,
category_id: 1,
note: 'Daily meeting with team',
complete: false,
},
{
id: 2,
category_id: 2,
note: 'Pay monthly rent',
complete: true,
},
{
id: 3,
category_id: 3,
note: 'Workout in the gym',
complete: false,
},
{
id: 4,
category_id: 1,
note: 'Make progress on project',
complete: false,
},
] as Note[],
});
export const markNote = (noteID: number) => {
const noteIndex = NoteStore.currentState.notes.findIndex((n) => n.id === noteID);
NoteStore.update((s) => {
s.notes[noteIndex].complete = !s.notes[noteIndex].complete;
});
document.getElementById(`noteRow_${noteID}`).classList.add('animate__pulse');
setTimeout(() => {
document.getElementById(`noteRow_${noteID}`).classList.remove('animate__pulse');
}, 500);
};
export const addNote = (note: Note) => {
NoteStore.update((s) => {
s.notes = [note, ...s.notes];
});
};
export default NoteStore;

View File

@@ -0,0 +1,16 @@
import { createSelector } from 'reselect';
import { Category, Note } from './NoteStore';
interface State {
categories: Category[];
notes: Note[];
}
const getState = (state: State) => state;
// General getters
export const getCategories = createSelector(getState, (state) => state.categories);
export const getNotes = createSelector(getState, (state) => state.notes);
// More specific getters
// export const getCoffee = (id: number) => createSelector(getState, state => state.coffees.filter(c => parseInt(c.id) === parseInt(id))[0]);

View File

@@ -0,0 +1,2 @@
export { default as CategoryStore } from "./CategoryStore";
export { default as NoteStore } from "./NoteStore";

View File

@@ -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;
}

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>
);
};

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