Skip to content
This repository was archived by the owner on Jun 7, 2025. It is now read-only.
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13,640 changes: 9,040 additions & 4,600 deletions package-lock.json

Large diffs are not rendered by default.

7 changes: 6 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
"type": "module",
"scripts": {
"dev": "vite dev --port 3000 --host",
"tunnel": "npx localtunnel --port 3000",
"dev:tunnel": "concurrently \"npm run dev\" \"npm run tunnel\"",
"build": "vite build",
"preview": "vite preview --port 3000 --host",
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
Expand All @@ -26,16 +28,19 @@
"@types/lodash-es": "^4.17.12",
"@types/mock-fs": "^4.13.4",
"@types/node": "^22.15.17",
"@vite-pwa/sveltekit": "^1.0.0",
"@vitest/coverage-v8": "^3.1.3",
"@vitest/ui": "^3.1.3",
"autoprefixer": "^10.4.21",
"c8": "^10.1.3",
"concurrently": "^9.1.2",
"coveralls-next": "^4.2.1",
"eslint": "^9.7.0",
"eslint-config-prettier": "^9.1.0",
"eslint-plugin-svelte": "^2.36.0",
"globals": "^15.0.0",
"jsdom": "^26.1.0",
"localtunnel": "^2.0.2",
"mock-fs": "^5.5.0",
"postcss": "^8.5.3",
"prettier": "^3.3.2",
Expand Down Expand Up @@ -63,4 +68,4 @@
"mode-watcher": "^0.5.0",
"vite": "^6.0.0"
}
}
}
76 changes: 76 additions & 0 deletions src/lib/components/PWAInstallPrompt.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
<script>
// @ts-ignore
import { logger } from '$lib/utils/logger';
import { browser } from '$app/environment';
let { data } = $props();

// @ts-ignore
let deferredPrompt = null;
let showButton = $state(false);
showButton = data?.showButton ? data.showButton : false; // for test

if (browser) {
// @ts-ignore
window.addEventListener('beforeinstallprompt', (e) => {
// Prevent the mini-info bar from appearing on mobile
e.preventDefault();
// Stash the event so it can be triggered later.
deferredPrompt = e;
// Update UI notify the user they can add to home screen
showButton = localStorage.getItem('dismissedPWAInstallPrompt') !== 'true';
console.log('beforeinstallprompt', e);
});


}

function installApp() {
// @ts-ignore
if (deferredPrompt) {
deferredPrompt.prompt();
// @ts-ignore
deferredPrompt.userChoice.then((choiceResult) => {
if (choiceResult.outcome === 'accepted') {
logger.log('Accepted the install prompt');
} else {
console.log('Rejected the install prompt');
}
deferredPrompt = null;
showButton = false;
});
}
}

function closePrompt() {
localStorage.setItem('dismissedPWAInstallPrompt', 'true');
showButton = false;
}
</script>

{#if showButton}
<div class="fixed bottom-0 left-0 right-0 bg-white text-purple-700 p-4 flex justify-between items-center z-10" style="box-shadow: 0 4px 10px rgba(0, 0, 0, 0.3);">
<div class="flex items-left gap-2 mr-2">
<!-- Logo -->
<img src="/web/icon-192.png" alt="App Icon" class="w-10 h-10 mr-2" />
<!-- App Name -->
<div class="flex flex-col items-start">
<span class="font-bold">SUPPL-AI</span>
<!-- Description -->
<span class="text-sm text-gray-600 mt-1">Installa l'app per un accesso rapido e facile</span>
</div>
</div>
<div class="flex gap-2 items-center">
<button
onclick={installApp}
class="item-primary rounded-full border-none p-3 text-center font-bold cursor-pointer">
Install
</button>
<button
onclick={closePrompt}
class="bg-none border-none text-2xl font-bold text-primary cursor-pointer">
&times;
</button>
</div>
</div>

{/if}
17 changes: 17 additions & 0 deletions src/routes/+layout.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@
import '../app.css';
import { browser } from '$app/environment';
import { logger } from '$lib/utils/logger';

import PwaInstallPrompt from '$lib/components/PWAInstallPrompt.svelte';
import { pwaInfo } from 'virtual:pwa-info';
let webManifestLink = pwaInfo?.webManifest?.linkTag ?? '';

let {
children,
data
Expand Down Expand Up @@ -40,6 +45,18 @@
}
}
});


</script>

<svelte:head>
<title>Suppl-AI</title>
{@html webManifestLink}
<link rel="apple-touch-icon" href="img/favicon.ico">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="default">
<meta name="apple-mobile-web-app-title" content="SUPPL-AI">

</svelte:head>
<PwaInstallPrompt />
{@render children?.()}
Binary file added static/screenshots/desktop.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added static/screenshots/mobile.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
18 changes: 18 additions & 0 deletions static/web/README.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
Add this to your HTML <head>:

<link rel="icon" href="/favicon.ico" sizes="any">
<link rel="apple-touch-icon" href="/apple-touch-icon.png">

Add this to your app's manifest.json:

...
{
"icons": [
{ "src": "/favicon.ico", "type": "image/x-icon", "sizes": "16x16 32x32" },
{ "src": "/icon-192.png", "type": "image/png", "sizes": "192x192" },
{ "src": "/icon-512.png", "type": "image/png", "sizes": "512x512" },
{ "src": "/icon-192-maskable.png", "type": "image/png", "sizes": "192x192", "purpose": "maskable" },
{ "src": "/icon-512-maskable.png", "type": "image/png", "sizes": "512x512", "purpose": "maskable" }
]
}
...
Binary file added static/web/apple-touch-icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added static/web/favicon.ico
Binary file not shown.
Binary file added static/web/icon-192-maskable.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added static/web/icon-192.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added static/web/icon-512-maskable.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added static/web/icon-512.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
12 changes: 12 additions & 0 deletions tests/lib/components/PWAInstallPrompt.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { render, screen } from '@testing-library/svelte';
import PWAInstallPrompt from '$lib/components/PWAInstallPrompt.svelte';

describe('PWAInstallPrompt', () => {

it('should render the install prompt when showButton is true', () => {
render(PWAInstallPrompt,{ data:{showButton: true }});

expect(screen.getByText('Install')).toBeInTheDocument();
});

});
2 changes: 1 addition & 1 deletion tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
"sourceMap": true,
"strict": true,
"moduleResolution": "bundler",
"types": ["vitest/globals"]
"types": ["vitest/globals", "vite-plugin-pwa/info"]
}
// Path aliases are handled by https://svelte.dev/docs/kit/configuration#alias
// except $lib which is handled by https://svelte.dev/docs/kit/configuration#files
Expand Down
77 changes: 61 additions & 16 deletions vite.config.ts
Original file line number Diff line number Diff line change
@@ -1,39 +1,84 @@
import { sveltekit } from '@sveltejs/kit/vite';
import { defineConfig } from 'vite';
import { SvelteKitPWA } from '@vite-pwa/sveltekit';

export default defineConfig(({ mode }) => ({
plugins: [sveltekit()],
plugins: [
sveltekit(),
SvelteKitPWA({
registerType: 'autoUpdate',
manifest: {
name: 'SUPPL-AI',
short_name: 'SupplAI',
description: 'Gestione intelligente dei documenti e FAQ',
theme_color: '#007bff',
background_color: '#ffffff',
display: 'standalone',
start_url: '/',
icons: [
{
src: 'web/icon-192.png',
sizes: '192x192',
type: 'image/png'
},
{
src: 'web/icon-512.png',
sizes: '512x512',
type: 'image/png'
}
],
screenshots: [
{
src: '/screenshots/mobile.png',
sizes: '1290x2796',
type: 'image/png',
form_factor: 'narrow'
},
{
src: '/screenshots/desktop.png',
sizes: '2560x1262',
type: 'image/png',
form_factor: 'wide'
}
]
},
devOptions: {
enabled: true
}
})
],
test: {
environment: 'jsdom',
globals: true,
setupFiles: './src/setupTests.ts',
passWithNoTests: true,
reporters: 'verbose',
reporters: 'verbose',
coverage: {
provider: 'v8',
reporter: ['text', 'html', 'lcov'],
reportsDirectory: './coverage',
exclude: [
'src/setupTests.ts',
'**/*.d.ts',
provider: 'v8',
reporter: ['text', 'html', 'lcov'],
reportsDirectory: './coverage',
exclude: [
'src/setupTests.ts',
'**/*.d.ts',
'.svelte-kit/**',
'**/*.config.ts',
'**/*.config.js',
'static/**',
'html/**',
'node_modules/**',
'src/lib/index.ts',
'src/lib/utils/logger.ts',
],
},
'src/lib/utils/logger.ts'
]
}
},
css: {
postcss: './postcss.config.js',
},
postcss: './postcss.config.js'
},
resolve: {
conditions: mode === 'test' ? ['browser'] : [],
conditions: mode === 'test' ? ['browser'] : []
},
server: {
cors: true
},
cors: true,
allowedHosts: ['.loca.lt']
}
}));