This project is a Progressive Web App (PWA) built with Next.js, React, and TypeScript. It uses Tailwind CSS for styling, Radix UI for accessible components, OneSignal for push notifications, and demonstrates access to the file system and webcam.
Installation
To get started with this project, clone the repository and install the dependencies:
git clone https://github.com/UbyXsofT/my-pwa-app.git
cd my-pwa-app
npm install
Development
To start the development server, run:
npm run dev
This will start the application in development mode at http://localhost:3000.
Build
o build the application for production, run:
npm run build
Features
- Progressive Web App (PWA): Offline support and installable on devices.
- Next.js: Server-side rendering and static site generation.
- React & TypeScript: Modern – JavaScript framework with static typing.
- Tailwind CSS: Utility-first CSS framework for rapid UI development.
- Radix UI: Accessible, unstyled UI component library.
- OneSignal: Push notifications.
- File System Access: Demonstrates access to the file system.
- Webcam Access: Demonstrates access to the webcam.
Usage
OneSignal Push Notifications
To set up OneSignal for push notifications, follow these steps:
1 – Download and unzip the OneSignal SDK: OneSignalSDK-v16-ServiceWorker.zip
2 – Add the unzipped files to the public
directory of your project.
3 – Modify the _document.tsx
to include OneSignalSDK:
//_document.tsx
import { Html, Head, Main, NextScript } from "next/document";
export default function Document() {
return (
<Html lang='en'>
<Head>
<link
rel='manifest'
href='/manifest.json'
/>
<link
rel='apple-touch-icon'
href='/icon.png'
/>
<meta
name='theme-color'
content='#fff'
/>
<script
src='https://cdn.onesignal.com/sdks/web/v16/OneSignalSDK.page.js'
async
></script>
</Head>
<body>
<Main />
<NextScript />
</body>
</Html>
);
}
4 – Initialize OneSignal in src/functions/onesignal.js
:
//src/functions/onesignal.js
import OneSignal from "react-onesignal";
export default async function runOneSignal() {
console.log("Inizializzazione OneSignal");
try {
await OneSignal.init({
appId: "YOUR-ONESIGNAL-APP-ID",
allowLocalhostAsSecureOrigin: true,
serviceWorkerParam: {
scope: "/",
path: "/OneSignalSDKWorker.js",
},
});
console.log("OneSignal inizializzato");
OneSignal.Slidedown.promptPush();
console.log("Prompt mostrato");
} catch (error) {
console.log("ONESIGNAL ERROR: ", error);
}
}
5 – Call runOneSignal
in src/pages/_app.tsx
:
import "../src/styles/globals.css";
import { AppProps } from "next/app";
import { useEffect } from "react";
import runOneSignal from "../src/functions/onesignal";
function MyApp({ Component, pageProps }: AppProps) {
useEffect(() => {
runOneSignal();
}, []);
return <Component {...pageProps} />;
}
export default MyApp;
File System Access
To use the File System Access API, you can create a component that allows users to pick a file and read its content. Here’s an example of a file picker component:
import { ReactNode, useState } from "react";
const FileSystemComponent = () => {
const [fileContent, setFileContent] = useState<string | ArrayBuffer | null>("");
const handleFilePick = async () => {
const [fileHandle] = await (window as any).showOpenFilePicker();
const file = await fileHandle.getFile();
const text = await file.text();
setFileContent(text);
};
return (
<div>
<button
style={{ margin: "20px" }}
onClick={handleFilePick}
>
Pick a file
</button>
<pre>{fileContent as ReactNode}</pre>
</div>
);
};
export default FileSystemComponent;
Webcam Access
To access the webcam, you can create a component that uses the MediaDevices API. Here’s an example of a webcam component:
import React, { useRef, useEffect } from "react";
const CameraComponent: React.FC = () => {
const videoRef = useRef<HTMLVideoElement>(null);
useEffect(() => {
const startCamera = async () => {
if (videoRef.current) {
try {
const stream: MediaStream = await navigator.mediaDevices.getUserMedia({ video: true });
if (videoRef.current) {
videoRef.current.srcObject = stream;
}
} catch (err) {
console.error("Error accessing camera: ", err);
}
}
};
startCamera();
}, []);
return (
<video
ref={videoRef}
autoPlay
style={{ width: "100%", height: "200px" }}
/>
);
};
export default CameraComponent;
Contributing
Contributions are always welcome!
See contributing.md
for ways to get started.
Please adhere to this project’s code of conduct
, please feel free to submit a pull request.
License
This project is licensed under the MIT License. See the LICENSE file for details.