first commit
This commit is contained in:
commit
34cf681f71
11 changed files with 6859 additions and 0 deletions
40
.gitignore
vendored
Normal file
40
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,40 @@
|
||||||
|
# --- Node ---
|
||||||
|
node_modules/
|
||||||
|
npm-debug.log*
|
||||||
|
yarn-debug.log*
|
||||||
|
yarn-error.log*
|
||||||
|
pnpm-debug.log*
|
||||||
|
|
||||||
|
# --- Capacitor ---
|
||||||
|
android/
|
||||||
|
ios/
|
||||||
|
capacitor.config.json.backup
|
||||||
|
app/public/build/
|
||||||
|
app/public/dist/
|
||||||
|
app/public/.vite/
|
||||||
|
|
||||||
|
# --- Electron ---
|
||||||
|
dist/
|
||||||
|
electron/
|
||||||
|
dist-electron/
|
||||||
|
out/
|
||||||
|
release/
|
||||||
|
build/
|
||||||
|
*.asar
|
||||||
|
|
||||||
|
# Electron Builder temp
|
||||||
|
*.dmg
|
||||||
|
*.zip
|
||||||
|
*.pkg
|
||||||
|
|
||||||
|
# --- System files ---
|
||||||
|
.DS_Store
|
||||||
|
Thumbs.db
|
||||||
|
|
||||||
|
# --- Logs ---
|
||||||
|
logs/
|
||||||
|
*.log
|
||||||
|
|
||||||
|
# --- Environment ---
|
||||||
|
.env
|
||||||
|
.env.*
|
||||||
218
README.md
Normal file
218
README.md
Normal file
|
|
@ -0,0 +1,218 @@
|
||||||
|
# MacOS con Capacitor Electon
|
||||||
|
|
||||||
|
creare un foder
|
||||||
|
|
||||||
|
inizializza Capacitor
|
||||||
|
|
||||||
|
```
|
||||||
|
npm install @capacitor/core @capacitor/cli
|
||||||
|
npx cap init
|
||||||
|
npx cap init "MyApps" "it.patachina.myapps" --web-dir=web
|
||||||
|
```
|
||||||
|
inserisci in name il nome che vuoi x es MyApps
|
||||||
|
|
||||||
|
in id xesemoio it.patachina.myapps
|
||||||
|
|
||||||
|
in Web asset directory metti web (la dir dove si trova il file statico)
|
||||||
|
|
||||||
|
aggiungi Electon
|
||||||
|
|
||||||
|
```
|
||||||
|
npm install @capacitor-community/electron electron
|
||||||
|
npx cap add @capacitor-community/electron
|
||||||
|
```
|
||||||
|
copia il file statico nella cartella web
|
||||||
|
|
||||||
|
per esempio
|
||||||
|
|
||||||
|
```
|
||||||
|
/web/index.html
|
||||||
|
/web/style.css
|
||||||
|
/web/app.js
|
||||||
|
```
|
||||||
|
|
||||||
|
build e sync
|
||||||
|
|
||||||
|
```
|
||||||
|
npx cap sync
|
||||||
|
```
|
||||||
|
avvia l'app macOS per testare se funziona
|
||||||
|
|
||||||
|
```
|
||||||
|
npx cap open @capacitor-community/electron
|
||||||
|
```
|
||||||
|
|
||||||
|
crea il pacchetto .app
|
||||||
|
|
||||||
|
```
|
||||||
|
npm install electron-builder --save-dev
|
||||||
|
```
|
||||||
|
|
||||||
|
modifica il tuo package.json inserendo alla fine
|
||||||
|
|
||||||
|
```
|
||||||
|
"scripts": {
|
||||||
|
"electron:build": "electron-builder -c electron-builder.json"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
oppure per una versione più semplice
|
||||||
|
|
||||||
|
```
|
||||||
|
"scripts": {
|
||||||
|
"electron:build": "electron-builder"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
inserisci anche i campi name,version,description,author,main
|
||||||
|
|
||||||
|
inoltre
|
||||||
|
|
||||||
|
```
|
||||||
|
"electron": "^39.2.7"
|
||||||
|
```
|
||||||
|
deve essere in devDependencies non dependencies
|
||||||
|
il file deve diventare
|
||||||
|
|
||||||
|
```
|
||||||
|
{
|
||||||
|
"name": "MyApps",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "Cross-platform launcher built with Capacitor and Electron",
|
||||||
|
"author": "Fabio",
|
||||||
|
"main": "electron/main.js",
|
||||||
|
"dependencies": {
|
||||||
|
"@capacitor-community/electron": "^5.0.1",
|
||||||
|
"@capacitor/cli": "^7.4.4",
|
||||||
|
"@capacitor/core": "^8.0.0"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"electron": "^39.2.7",
|
||||||
|
"electron-builder": "^26.0.12"
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"electron:build": "electron-builder -c electron-builder.json"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
nella root aggiungi il file electron-builder.json
|
||||||
|
|
||||||
|
```
|
||||||
|
{
|
||||||
|
"appId": "it.fabio.myapps",
|
||||||
|
"productName": "MyApps",
|
||||||
|
"directories": {
|
||||||
|
"output": "dist-electron"
|
||||||
|
},
|
||||||
|
"files": [
|
||||||
|
"electron/**/*",
|
||||||
|
"web/**/*"
|
||||||
|
],
|
||||||
|
"mac": {
|
||||||
|
"category": "public.app-category.productivity",
|
||||||
|
"icon": "electron/assets/casina.icns",
|
||||||
|
"identity": null,
|
||||||
|
"hardenedRuntime": false,
|
||||||
|
"gatekeeperAssess": false,
|
||||||
|
"notarize": false
|
||||||
|
},
|
||||||
|
"win": {
|
||||||
|
"target": "nsis"
|
||||||
|
},
|
||||||
|
"linux": {
|
||||||
|
"target": "AppImage"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
visti i tempi lunghi di certificazione solo quando va bene puoi modificare in
|
||||||
|
|
||||||
|
```
|
||||||
|
"identity": "MyCustomCert",
|
||||||
|
```
|
||||||
|
vedi sotto come creare la MyCustomCert
|
||||||
|
|
||||||
|
copiare casina.icns (macos vuole solo quella estensione)
|
||||||
|
|
||||||
|
```
|
||||||
|
cp icons/casina.icns electron/assets/
|
||||||
|
```
|
||||||
|
|
||||||
|
in electron/assets/
|
||||||
|
|
||||||
|
creare in electron il file main.js
|
||||||
|
|
||||||
|
```
|
||||||
|
nano electron/main.js
|
||||||
|
```
|
||||||
|
e inserire
|
||||||
|
|
||||||
|
```
|
||||||
|
// electron/main.js
|
||||||
|
const { app, BrowserWindow } = require('electron');
|
||||||
|
const path = require('path');
|
||||||
|
|
||||||
|
function createWindow() {
|
||||||
|
const win = new BrowserWindow({
|
||||||
|
width: 1200,
|
||||||
|
height: 800,
|
||||||
|
webPreferences: {
|
||||||
|
preload: path.join(__dirname, 'preload.js')
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
win.loadFile(path.join(__dirname, '../web/index.html'));
|
||||||
|
}
|
||||||
|
|
||||||
|
app.whenReady().then(() => {
|
||||||
|
createWindow();
|
||||||
|
|
||||||
|
app.on('activate', () => {
|
||||||
|
if (BrowserWindow.getAllWindows().length === 0) createWindow();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
app.on('window-all-closed', () => {
|
||||||
|
if (process.platform !== 'darwin') app.quit();
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
ora puoi builare
|
||||||
|
|
||||||
|
```
|
||||||
|
npm run electron:build
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
## Genera chiave privata + certificato con estensioni Code Signing
|
||||||
|
|
||||||
|
```
|
||||||
|
openssl req -x509 -nodes -days 365 \
|
||||||
|
-newkey rsa:2048 \
|
||||||
|
-keyout mycert.key \
|
||||||
|
-out mycert.crt \
|
||||||
|
-config codesign.cnf
|
||||||
|
```
|
||||||
|
Unisci chiave + certificato in un PEM
|
||||||
|
|
||||||
|
```
|
||||||
|
cat mycert.key mycert.crt > mycert.pem
|
||||||
|
```
|
||||||
|
|
||||||
|
Importa nel portachiavi login
|
||||||
|
````
|
||||||
|
security import mycert.pem -k ~/Library/Keychains/login.keychain-db -A
|
||||||
|
```
|
||||||
|
|
||||||
|
rendere il certificato attendibile per la firma codice
|
||||||
|
|
||||||
|
1️⃣ Apri Accesso Portachiavi
|
||||||
|
Applicazioni → Utility → Accesso Portachiavi
|
||||||
|
|
||||||
|
2️⃣ Colonna sinistra → seleziona login
|
||||||
|
3️⃣ Colonna centrale → vai su I miei certificati
|
||||||
|
4️⃣ Fai doppio clic su MyCustomCert
|
||||||
|
5️⃣ Vai nella sezione Attendibilità
|
||||||
|
6️⃣ Imposta:
|
||||||
|
👉 Quando si usa questo certificato: Considera sempre attendibile
|
||||||
|
7️⃣ Chiudi la finestra
|
||||||
|
macOS ti chiede la password → conferma.
|
||||||
161
README2.md
Normal file
161
README2.md
Normal file
|
|
@ -0,0 +1,161 @@
|
||||||
|
# MacOS con Capacitor Electon (non funziona)
|
||||||
|
|
||||||
|
creare un foder per esempio launch ed entraci
|
||||||
|
|
||||||
|
```
|
||||||
|
mkdir launch
|
||||||
|
cd launch
|
||||||
|
```
|
||||||
|
crea una cartella per il file statico, in questo caso web
|
||||||
|
|
||||||
|
```
|
||||||
|
mkdir web
|
||||||
|
```
|
||||||
|
|
||||||
|
copia il file statico nella cartella web
|
||||||
|
|
||||||
|
per esempio
|
||||||
|
|
||||||
|
```
|
||||||
|
/web/index.html
|
||||||
|
/web/style.css
|
||||||
|
/web/app.js
|
||||||
|
```
|
||||||
|
|
||||||
|
inizializza capacitor
|
||||||
|
|
||||||
|
```
|
||||||
|
npm init -y
|
||||||
|
npm install @capacitor/core @capacitor/cli
|
||||||
|
npx cap init "MyApps" "it.patachina.myapps" --web-dir=web
|
||||||
|
```
|
||||||
|
|
||||||
|
qui ho chiamato la mia app "MyApps", l'ID della app "it.patachina.myapps" e la webdir quella creata prima "web"
|
||||||
|
|
||||||
|
ora aggiungo Electron come piattaforma a Capacitor
|
||||||
|
|
||||||
|
```
|
||||||
|
npm install @capacitor-community/electron
|
||||||
|
npx cap add @capacitor-community/electron
|
||||||
|
```
|
||||||
|
|
||||||
|
inserisci in capacitor.config.json
|
||||||
|
|
||||||
|
```
|
||||||
|
"bundledWebRuntime": false
|
||||||
|
```
|
||||||
|
|
||||||
|
copia i file statici dentro Electron
|
||||||
|
|
||||||
|
```
|
||||||
|
npx cap copy
|
||||||
|
```
|
||||||
|
|
||||||
|
questo copia i file statici in electron/app
|
||||||
|
|
||||||
|
entra in electron
|
||||||
|
|
||||||
|
```
|
||||||
|
cd electron
|
||||||
|
```
|
||||||
|
e se il progetto non è ts ma solo js modifica tsconfig.json
|
||||||
|
|
||||||
|
```
|
||||||
|
nano tsconfig.json
|
||||||
|
```
|
||||||
|
|
||||||
|
inserendo in compileOptions types e skipLibCheck
|
||||||
|
|
||||||
|
```
|
||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"types": ["node"],
|
||||||
|
"skipLibCheck": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
per creare .dmg file bisogna installare electron build (sempre nella directory electron)
|
||||||
|
|
||||||
|
```
|
||||||
|
npm install -D electron-builder
|
||||||
|
```
|
||||||
|
in package.json sempre dentro electron aggiungi negli scripts la sezione "electron:build"
|
||||||
|
|
||||||
|
```
|
||||||
|
"scripts": {
|
||||||
|
"electron:build": "electron-builder"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
e aggiungi (o verifica) la sezione build (dove ho messo name, ID, risoluzione)
|
||||||
|
|
||||||
|
inoltre l'icona casina.icns che era nel file statico in web, se non ho l'icona rimuovo "icon" userà quella di default
|
||||||
|
|
||||||
|
inserito anche identity, per crearla vedi sotto
|
||||||
|
|
||||||
|
```
|
||||||
|
{
|
||||||
|
"name": "MyApps",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"build": {
|
||||||
|
"appId": "it.patachina.myapps",
|
||||||
|
"files": [
|
||||||
|
"build/**/*",
|
||||||
|
"package.json"
|
||||||
|
],
|
||||||
|
"mac": {
|
||||||
|
"target": ["dmg", "zip"],
|
||||||
|
"category": "public.app-category.productivity",
|
||||||
|
"icon": "app/casina.icns",
|
||||||
|
"identity": "MyCustomCert",
|
||||||
|
"hardenedRuntime": false,
|
||||||
|
"gatekeeperAssess": false
|
||||||
|
},
|
||||||
|
"dmg": {
|
||||||
|
"background": null,
|
||||||
|
"window": {
|
||||||
|
"width": 540,
|
||||||
|
"height": 380
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"description": "An Amazing Capacitor App",
|
||||||
|
```
|
||||||
|
|
||||||
|
costruisci il build e fallo partire
|
||||||
|
```
|
||||||
|
npm run build
|
||||||
|
npm run electron:start
|
||||||
|
```
|
||||||
|
|
||||||
|
per creare .dmg file, sempre in electron, eseguire il Comando per generare il DMG
|
||||||
|
|
||||||
|
```
|
||||||
|
npm run electron:build
|
||||||
|
```
|
||||||
|
|
||||||
|
## Crea autocertificato
|
||||||
|
|
||||||
|
Crea un file di configurazione OpenSSL
|
||||||
|
Crea codesign.cnf:
|
||||||
|
|
||||||
|
```
|
||||||
|
cat <<EOF > codesign.cnf
|
||||||
|
[ req ]
|
||||||
|
default_bits = 2048
|
||||||
|
prompt = no
|
||||||
|
default_md = sha256
|
||||||
|
distinguished_name = dn
|
||||||
|
x509_extensions = ext
|
||||||
|
|
||||||
|
[ dn ]
|
||||||
|
CN = MyCustomCert
|
||||||
|
|
||||||
|
[ ext ]
|
||||||
|
keyUsage = critical, digitalSignature
|
||||||
|
extendedKeyUsage = critical, codeSigning
|
||||||
|
basicConstraints = critical, CA:FALSE
|
||||||
|
EOF
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
5
capacitor.config.json
Normal file
5
capacitor.config.json
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
{
|
||||||
|
"appId": "it.patachina.myapps",
|
||||||
|
"appName": "MyApps",
|
||||||
|
"webDir": "web"
|
||||||
|
}
|
||||||
25
electron-builder.json
Normal file
25
electron-builder.json
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
{
|
||||||
|
"appId": "it.fabio.myapps",
|
||||||
|
"productName": "MyApps",
|
||||||
|
"directories": {
|
||||||
|
"output": "dist-electron"
|
||||||
|
},
|
||||||
|
"files": [
|
||||||
|
"electron/**/*",
|
||||||
|
"web/**/*"
|
||||||
|
],
|
||||||
|
"mac": {
|
||||||
|
"category": "public.app-category.productivity",
|
||||||
|
"icon": "electron/assets/casina.icns",
|
||||||
|
"identity": null,
|
||||||
|
"hardenedRuntime": false,
|
||||||
|
"gatekeeperAssess": false,
|
||||||
|
"notarize": false
|
||||||
|
},
|
||||||
|
"win": {
|
||||||
|
"target": "nsis"
|
||||||
|
},
|
||||||
|
"linux": {
|
||||||
|
"target": "AppImage"
|
||||||
|
}
|
||||||
|
}
|
||||||
BIN
icons/casina.icns
Normal file
BIN
icons/casina.icns
Normal file
Binary file not shown.
5078
package-lock.json
generated
Normal file
5078
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load diff
19
package.json
Normal file
19
package.json
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
{
|
||||||
|
"name": "MyApps",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "Cross-platform launcher built with Capacitor and Electron",
|
||||||
|
"author": "Fabio",
|
||||||
|
"main": "electron/main.js",
|
||||||
|
"dependencies": {
|
||||||
|
"@capacitor-community/electron": "^5.0.1",
|
||||||
|
"@capacitor/cli": "^7.4.4",
|
||||||
|
"@capacitor/core": "^8.0.0"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"electron-builder": "^26.4.0",
|
||||||
|
"electron": "^39.2.7"
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"electron:build": "electron-builder"
|
||||||
|
}
|
||||||
|
}
|
||||||
1006
web/app.js
Normal file
1006
web/app.js
Normal file
File diff suppressed because it is too large
Load diff
48
web/index.html
Normal file
48
web/index.html
Normal file
|
|
@ -0,0 +1,48 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="it">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<title>MyApps Launcher</title>
|
||||||
|
|
||||||
|
<!-- Blocca lo zoom del browser -->
|
||||||
|
<meta name="viewport"
|
||||||
|
content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
|
||||||
|
|
||||||
|
<link rel="stylesheet" href="style.css">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="setup-page" class="hidden">
|
||||||
|
<h2>Configurazione</h2>
|
||||||
|
|
||||||
|
<button id="cfg-refresh">Aggiorna ora</button>
|
||||||
|
|
||||||
|
<label>URL</label>
|
||||||
|
<input id="cfg-url" type="text">
|
||||||
|
|
||||||
|
<label>User</label>
|
||||||
|
<input id="cfg-user" type="text">
|
||||||
|
|
||||||
|
<label>Password</label>
|
||||||
|
<input id="cfg-pass" type="password">
|
||||||
|
|
||||||
|
<button id="cfg-save">Salva</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Griglia icone -->
|
||||||
|
<div class="folder" id="folder"></div>
|
||||||
|
|
||||||
|
<!-- Menu contestuale -->
|
||||||
|
<div id="context-menu" class="context-menu hidden">
|
||||||
|
<button data-action="rename">Rinomina</button>
|
||||||
|
<button data-action="change-icon">Cambia icona</button>
|
||||||
|
<button data-action="remove">Rimuovi</button>
|
||||||
|
</div>
|
||||||
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.1.1/crypto-js.min.js"></script>
|
||||||
|
<script src="app.js"></script>
|
||||||
|
|
||||||
|
<!-- <script src="https://cdn.jsdelivr.net/npm/eruda"></script>
|
||||||
|
<script>
|
||||||
|
eruda.init();
|
||||||
|
</script> -->
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
259
web/style.css
Normal file
259
web/style.css
Normal file
|
|
@ -0,0 +1,259 @@
|
||||||
|
/* ============================================================
|
||||||
|
BASE PAGE
|
||||||
|
============================================================ */
|
||||||
|
|
||||||
|
html, body {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
overflow-x: hidden; /* impedisce pan orizzontale */
|
||||||
|
max-width: 100%;
|
||||||
|
touch-action: pan-y; /* solo scroll verticale */
|
||||||
|
background: #ffffff;
|
||||||
|
/*background: radial-gradient(circle at top, #f8f9ff 0%, #e6e8ef 60%, #dcdfe6 100%);*/
|
||||||
|
font-family: system-ui, -apple-system, BlinkMacSystemFont, sans-serif;
|
||||||
|
color: #1a1a1a;
|
||||||
|
min-height: 100vh; /* evita scroll inutile se poche icone */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Impedisce selezione testo e highlight blu Android */
|
||||||
|
* {
|
||||||
|
-webkit-user-select: none;
|
||||||
|
user-select: none;
|
||||||
|
-webkit-tap-highlight-color: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Variabile di zoom globale */
|
||||||
|
:root {
|
||||||
|
--zoom: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ============================================================
|
||||||
|
GRIGLIA ICONE
|
||||||
|
============================================================ */
|
||||||
|
|
||||||
|
.folder {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(
|
||||||
|
auto-fill,
|
||||||
|
minmax(calc(85px * var(--zoom)), 1fr)
|
||||||
|
);
|
||||||
|
gap: calc(16px * var(--zoom));
|
||||||
|
padding-top: 24px;
|
||||||
|
padding-left: 24px;
|
||||||
|
padding-right: 24px;
|
||||||
|
padding-bottom: 0;
|
||||||
|
justify-items: start; /* più coerente con iOS */
|
||||||
|
width: 100%;
|
||||||
|
max-width: 100%;
|
||||||
|
box-sizing: border-box;
|
||||||
|
|
||||||
|
transition: grid-template-columns 0.15s ease-out,
|
||||||
|
gap 0.15s ease-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Contenitore icona — versione glass */
|
||||||
|
.app-icon {
|
||||||
|
text-align: center;
|
||||||
|
cursor: pointer;
|
||||||
|
user-select: none;
|
||||||
|
touch-action: none;
|
||||||
|
transition: transform 0.18s ease, filter 0.18s ease;
|
||||||
|
|
||||||
|
/* GLASS */
|
||||||
|
background: rgba(255, 255, 255, 0.12);
|
||||||
|
backdrop-filter: blur(10px);
|
||||||
|
-webkit-backdrop-filter: blur(10px);
|
||||||
|
|
||||||
|
border-radius: calc(20px * var(--zoom));
|
||||||
|
padding: calc(6px * var(--zoom));
|
||||||
|
box-sizing: border-box;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Icona PNG */
|
||||||
|
.app-icon img {
|
||||||
|
width: calc(78px * var(--zoom));
|
||||||
|
height: calc(78px * var(--zoom));
|
||||||
|
border-radius: calc(16px * var(--zoom));
|
||||||
|
background: transparent;
|
||||||
|
pointer-events: none;
|
||||||
|
|
||||||
|
box-shadow:
|
||||||
|
0 4px 10px rgba(0, 0, 0, 0.12),
|
||||||
|
0 8px 24px rgba(0, 0, 0, 0.08);
|
||||||
|
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Etichetta */
|
||||||
|
.app-icon span {
|
||||||
|
display: block;
|
||||||
|
margin-top: calc(6px * var(--zoom));
|
||||||
|
font-size: calc(11px * var(--zoom));
|
||||||
|
color: #3a3a3a;
|
||||||
|
font-weight: 500;
|
||||||
|
letter-spacing: -0.2px;
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
|
||||||
|
transition: font-size 0.18s ease-out,
|
||||||
|
margin-top 0.18s ease-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* ============================================================
|
||||||
|
WIGGLE MODE
|
||||||
|
============================================================ */
|
||||||
|
|
||||||
|
@keyframes wiggle {
|
||||||
|
0% { transform: rotate(-2deg) scale(1.02); }
|
||||||
|
50% { transform: rotate( 2deg) scale(0.98); }
|
||||||
|
100% { transform: rotate(-2deg) scale(1.02); }
|
||||||
|
}
|
||||||
|
|
||||||
|
.edit-mode .app-icon:not(.dragging) img {
|
||||||
|
animation: wiggle 0.25s ease-in-out infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Icona trascinata */
|
||||||
|
.app-icon.dragging {
|
||||||
|
opacity: 0.9;
|
||||||
|
z-index: 1000;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Placeholder invisibile */
|
||||||
|
.app-icon.placeholder {
|
||||||
|
opacity: 0;
|
||||||
|
visibility: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ============================================================
|
||||||
|
MENU CONTESTUALE — ANDROID MATERIAL + RESPONSIVE ALLO ZOOM
|
||||||
|
============================================================ */
|
||||||
|
|
||||||
|
#context-menu {
|
||||||
|
position: fixed;
|
||||||
|
background: #ffffff;
|
||||||
|
border-radius: calc(14px * var(--zoom));
|
||||||
|
min-width: calc(180px * var(--zoom));
|
||||||
|
padding: calc(8px * var(--zoom)) 0;
|
||||||
|
z-index: 2000;
|
||||||
|
|
||||||
|
/* Ombra Material */
|
||||||
|
box-shadow:
|
||||||
|
0 calc(6px * var(--zoom)) calc(20px * var(--zoom)) rgba(0,0,0,0.18),
|
||||||
|
0 calc(2px * var(--zoom)) calc(6px * var(--zoom)) rgba(0,0,0,0.12);
|
||||||
|
|
||||||
|
/* Animazione apertura */
|
||||||
|
opacity: 0;
|
||||||
|
transform: scale(0.85);
|
||||||
|
transform-origin: top center;
|
||||||
|
transition: opacity 120ms ease, transform 120ms ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
#context-menu:not(.hidden) {
|
||||||
|
opacity: 1;
|
||||||
|
transform: scale(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
#context-menu.hidden {
|
||||||
|
display: block;
|
||||||
|
opacity: 0;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Pulsanti del menù */
|
||||||
|
#context-menu button {
|
||||||
|
all: unset;
|
||||||
|
width: 100%;
|
||||||
|
padding: calc(14px * var(--zoom)) calc(18px * var(--zoom));
|
||||||
|
font-size: calc(15px * var(--zoom));
|
||||||
|
color: #222;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: calc(12px * var(--zoom));
|
||||||
|
cursor: pointer;
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Ripple effect */
|
||||||
|
#context-menu button::after {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
inset: 0;
|
||||||
|
background: rgba(0,0,0,0.08);
|
||||||
|
opacity: 0;
|
||||||
|
transition: opacity 150ms;
|
||||||
|
}
|
||||||
|
|
||||||
|
#context-menu button:active::after {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Separatore tra voci */
|
||||||
|
#context-menu button + button {
|
||||||
|
border-top: 1px solid rgba(0,0,0,0.08);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Voce "Rimuovi" in rosso */
|
||||||
|
#context-menu button:last-child {
|
||||||
|
color: #d11a2a;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* Permette drag sia mouse che touch */
|
||||||
|
.app-icon {
|
||||||
|
touch-action: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Evita che l'immagine intercetti eventi */
|
||||||
|
.app-icon img {
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Allineamento stile iOS, evita offset su PC */
|
||||||
|
.folder {
|
||||||
|
justify-items: start;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ============================================================
|
||||||
|
PAGINA INIZIALE
|
||||||
|
============================================================ */
|
||||||
|
|
||||||
|
#setup-page {
|
||||||
|
position: fixed;
|
||||||
|
inset: 0;
|
||||||
|
background: #f5f5f7;
|
||||||
|
padding: 40px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 16px;
|
||||||
|
z-index: 9999;
|
||||||
|
}
|
||||||
|
|
||||||
|
#setup-page.hidden {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
#setup-page input {
|
||||||
|
padding: 12px;
|
||||||
|
font-size: 16px;
|
||||||
|
border-radius: 8px;
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
}
|
||||||
|
|
||||||
|
#setup-page button {
|
||||||
|
padding: 14px;
|
||||||
|
font-size: 16px;
|
||||||
|
border-radius: 8px;
|
||||||
|
background: #007aff;
|
||||||
|
color: white;
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
#cfg-refresh {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
Loading…
Reference in a new issue