mirror of
https://github.com/manualdousuario/marreta.git
synced 2025-04-25 16:09:10 +00:00
adicionado suporte a pwa para compartilhamento rapido
This commit is contained in:
parent
c5c3b4c784
commit
592c5d0a2e
11 changed files with 166 additions and 6 deletions
|
@ -1,8 +1,18 @@
|
|||
/**
|
||||
* JavaScript functions for form validation and error handling
|
||||
* Funções JavaScript para validação de formulário e manipulação de erros
|
||||
*/
|
||||
|
||||
/**
|
||||
* Validates the form before submission
|
||||
*
|
||||
* Checks:
|
||||
* - If URL is not empty
|
||||
* - If URL starts with http:// or https://
|
||||
* - If URL has a valid format
|
||||
*
|
||||
* @returns {boolean} True if URL is valid, False otherwise
|
||||
*
|
||||
* Valida o formulário antes do envio
|
||||
*
|
||||
* Verifica:
|
||||
|
@ -17,18 +27,21 @@ function validateForm() {
|
|||
const submitButton = document.querySelector('button[type="submit"]');
|
||||
const url = urlInput.value.trim();
|
||||
|
||||
// Check if URL is not empty
|
||||
// Verifica se a URL não está vazia
|
||||
if (!url) {
|
||||
showError('Por favor, insira uma URL');
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if URL starts with http:// or https://
|
||||
// Verifica se a URL começa com http:// ou https://
|
||||
if (!/^https?:\/\//i.test(url)) {
|
||||
showError('A URL deve começar com http:// ou https://');
|
||||
return false;
|
||||
}
|
||||
|
||||
// Try to create a URL object to validate format
|
||||
// Tenta criar um objeto URL para validar o formato
|
||||
try {
|
||||
new URL(url);
|
||||
|
@ -37,16 +50,19 @@ function validateForm() {
|
|||
return false;
|
||||
}
|
||||
|
||||
// Disable input and button
|
||||
// Desabilita o input e o botão
|
||||
urlInput.readonly = true;
|
||||
submitButton.disabled = true;
|
||||
|
||||
// Add Tailwind disabled classes
|
||||
// Adiciona classes de disabled do Tailwind
|
||||
submitButton.classList.add('cursor-wait', 'disabled:bg-blue-400');
|
||||
submitButton.classList.remove('hover:bg-blue-700');
|
||||
|
||||
urlInput.classList.add('cursor-wait', 'disabled:bg-gray-50', 'focus:outline-none');
|
||||
|
||||
// Add loading state to button
|
||||
// Adiciona estado de loading ao botão
|
||||
submitButton.innerHTML = `
|
||||
<img src="assets/svg/search.svg" class="w-6 h-6 mr-3" alt="Search">
|
||||
|
@ -57,6 +73,13 @@ function validateForm() {
|
|||
}
|
||||
|
||||
/**
|
||||
* Displays an error message below the form
|
||||
*
|
||||
* Removes any existing error message before displaying the new one.
|
||||
* The message is displayed with an error icon and red formatting.
|
||||
*
|
||||
* @param {string} message Error message to be displayed
|
||||
*
|
||||
* Exibe uma mensagem de erro abaixo do formulário
|
||||
*
|
||||
* Remove qualquer mensagem de erro existente antes de exibir a nova.
|
||||
|
@ -68,11 +91,13 @@ function showError(message) {
|
|||
const form = document.getElementById('urlForm');
|
||||
const existingError = form.querySelector('.error-message');
|
||||
|
||||
// Remove previous error message if it exists
|
||||
// Remove mensagem de erro anterior se existir
|
||||
if (existingError) {
|
||||
existingError.remove();
|
||||
}
|
||||
|
||||
// Create and add new error message
|
||||
// Cria e adiciona nova mensagem de erro
|
||||
const errorDiv = document.createElement('div');
|
||||
errorDiv.className = 'error-message mt-4 text-base text-red-600';
|
||||
|
@ -82,3 +107,24 @@ function showError(message) {
|
|||
|
||||
form.appendChild(errorDiv);
|
||||
}
|
||||
|
||||
/**
|
||||
* Service Worker registration for PWA functionality
|
||||
* Registers a service worker to enable offline capabilities and PWA features
|
||||
*
|
||||
* Registro do Service Worker para funcionalidade PWA
|
||||
* Registra um service worker para habilitar recursos offline e funcionalidades PWA
|
||||
*/
|
||||
if ('serviceWorker' in navigator) {
|
||||
window.addEventListener('load', () => {
|
||||
navigator.serviceWorker.register('/service-worker.js')
|
||||
.then(() => {
|
||||
// Service Worker registered successfully
|
||||
// Service Worker registrado com sucesso
|
||||
})
|
||||
.catch(() => {
|
||||
// Service Worker registration failed
|
||||
// Falha no registro do Service Worker
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
BIN
app/assets/pwa/192x192.png
Normal file
BIN
app/assets/pwa/192x192.png
Normal file
Binary file not shown.
After ![]() (image error) Size: 5.6 KiB |
BIN
app/assets/pwa/512x512.png
Normal file
BIN
app/assets/pwa/512x512.png
Normal file
Binary file not shown.
After ![]() (image error) Size: 19 KiB |
|
@ -62,7 +62,13 @@ $cache_folder = $cache->getCacheFileCount();
|
|||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title><?php echo SITE_NAME; ?></title>
|
||||
<link rel="icon" href="assets/svg/marreta.svg" type="image/svg+xml">
|
||||
<link rel="icon" href="<?php echo SITE_URL; ?>/assets/svg/marreta.svg" type="image/svg+xml">
|
||||
<link rel="manifest" href="<?php echo SITE_URL; ?>/manifest.json">
|
||||
<meta name="theme-color" content="#2563eb">
|
||||
<meta name="apple-mobile-web-app-capable" content="yes">
|
||||
<meta name="apple-mobile-web-app-status-bar-style" content="black">
|
||||
<meta name="apple-mobile-web-app-title" content="<?php echo SITE_NAME; ?>">
|
||||
<link rel="apple-touch-icon" href="<?php echo SITE_URL; ?>/assets/pwa/192x192.png">
|
||||
<meta property="og:type" content="website" />
|
||||
<meta property="og:url" content="<?php echo SITE_URL; ?>" />
|
||||
<meta property="og:title" content="<?php echo SITE_NAME; ?>" />
|
||||
|
@ -148,6 +154,26 @@ $cache_folder = $cache->getCacheFileCount();
|
|||
<pre class="bg-gray-100 p-3 rounded-lg text-sm overflow-x-auto"><?php echo SITE_URL; ?>/p/https://exemplo.com</pre>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<!-- Adicionar como aplicativo / Add as app -->
|
||||
<div class="bg-white rounded-xl shadow-lg p-8 mt-8">
|
||||
<h2 class="text-xl font-semibold text-gray-800 mb-6 flex items-center">
|
||||
<img src="assets/svg/marreta.svg" class="w-6 h-6 mr-3" alt="App">
|
||||
<?php echo Language::get('add_as_app'); ?>
|
||||
</h2>
|
||||
<div class="space-y-4">
|
||||
<p class="text-gray-600">
|
||||
<?php echo str_replace('{site_name}', SITE_NAME, Language::get('add_as_app_description')); ?>
|
||||
</p>
|
||||
<div class="bg-gray-50 rounded-lg p-4">
|
||||
<ol class="list-decimal list-inside space-y-2 text-gray-700">
|
||||
<li><?php echo Language::get('add_as_app_step1'); ?></li>
|
||||
<li><?php echo Language::get('add_as_app_step2'); ?></li>
|
||||
<li><?php echo str_replace('{site_name}', SITE_NAME, Language::get('add_as_app_step3')); ?></li>
|
||||
</ol>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Seção de Bookmarklet / Bookmarklet section -->
|
||||
<div class="bg-white rounded-xl shadow-lg p-8 mt-8 mb-8">
|
||||
|
|
|
@ -17,6 +17,11 @@ return [
|
|||
'open_source_title' => 'Open Source Projekt',
|
||||
'open_source_description' => 'Das ist ein <a href="https://github.com/manualdousuario/marreta/" class="underline" target="_blank">Open Source</a> Projekt das mit ❤️ erstellt wurde!<br />Sie können einen Beitrag leisten, Probleme melden oder Vorschläge machen über <a href="https://github.com/manualdousuario/marreta/" class="underline" target="_blank">GitHub</a>.',
|
||||
'adblocker_warning' => 'Bei Konflikten zwischen {site_name} und Werbeblockern kann ein weißer Bildschirm angezeigt werden. Verwenden Sie den Inkognito-Modus oder deaktivieren Sie die Erweiterung.',
|
||||
'add_as_app' => 'Als App hinzufügen',
|
||||
'add_as_app_description' => 'Installieren Sie {site_name} als App für schnelles Link-Sharing:',
|
||||
'add_as_app_step1' => 'Klicken Sie in Ihrem Browser auf das Menüsymbol (drei Punkte)',
|
||||
'add_as_app_step2' => 'Wählen Sie "App installieren" oder "Zum Startbildschirm hinzufügen"',
|
||||
'add_as_app_step3' => 'Klicken Sie auf "Installieren" für schnellen Zugriff auf {site_name}',
|
||||
|
||||
'messages' => [
|
||||
'BLOCKED_DOMAIN' => [
|
||||
|
@ -52,4 +57,4 @@ return [
|
|||
'type' => 'warning'
|
||||
]
|
||||
]
|
||||
];
|
||||
];
|
||||
|
|
|
@ -17,6 +17,11 @@ return [
|
|||
'open_source_title' => 'Open Source Project',
|
||||
'open_source_description' => 'This is an <a href="https://github.com/manualdousuario/marreta/" class="underline" target="_blank">open source</a> project made with ❤️!<br />You can contribute, report issues, or make suggestions through <a href="https://github.com/manualdousuario/marreta/" class="underline" target="_blank">GitHub</a>.',
|
||||
'adblocker_warning' => 'Conflicts between {site_name} and ad blockers may cause a white screen. Use incognito mode or disable the extension.',
|
||||
'add_as_app' => 'Add as App',
|
||||
'add_as_app_description' => 'Install {site_name} as an app for quick link sharing:',
|
||||
'add_as_app_step1' => 'In your browser, click the menu icon (three dots)',
|
||||
'add_as_app_step2' => 'Select "Install app" or "Add to home screen"',
|
||||
'add_as_app_step3' => 'Click "Install" for quick access to {site_name}',
|
||||
|
||||
'messages' => [
|
||||
'BLOCKED_DOMAIN' => [
|
||||
|
@ -52,4 +57,4 @@ return [
|
|||
'type' => 'warning'
|
||||
]
|
||||
]
|
||||
];
|
||||
];
|
||||
|
|
|
@ -17,6 +17,11 @@ return [
|
|||
'open_source_title' => 'Proyecto de Código Abierto',
|
||||
'open_source_description' => '¡Este es un proyecto de <a href="https://github.com/manualdousuario/marreta/" class="underline" target="_blank">código abierto</a> hecho con ❤️!<br />Puedes contribuir, reportar problemas o hacer sugerencias a través de <a href="https://github.com/manualdousuario/marreta/" class="underline" target="_blank">GitHub</a>.',
|
||||
'adblocker_warning' => 'Los conflictos entre {site_name} y los bloqueadores de anuncios pueden causar una pantalla en blanco. Use el modo incógnito o desactive la extensión.',
|
||||
'add_as_app' => 'Agregar como Aplicación',
|
||||
'add_as_app_description' => 'Instale {site_name} como una aplicación para compartir enlaces rápidamente:',
|
||||
'add_as_app_step1' => 'En su navegador, haga clic en el icono de menú (tres puntos)',
|
||||
'add_as_app_step2' => 'Seleccione "Instalar aplicación" o "Agregar a la pantalla de inicio"',
|
||||
'add_as_app_step3' => 'Haga clic en "Instalar" para tener acceso rápido a {site_name}',
|
||||
|
||||
'messages' => [
|
||||
'BLOCKED_DOMAIN' => [
|
||||
|
@ -52,4 +57,4 @@ return [
|
|||
'type' => 'warning'
|
||||
]
|
||||
]
|
||||
];
|
||||
];
|
||||
|
|
|
@ -17,6 +17,11 @@ return [
|
|||
'open_source_title' => 'Projeto Open Source',
|
||||
'open_source_description' => 'Este é um projeto de <a href="https://github.com/manualdousuario/marreta/" class="underline" target="_blank">código aberto</a> feito com ❤️!<br />Você pode contribuir, reportar problemas ou fazer sugestões através do <a href="https://github.com/manualdousuario/marreta/" class="underline" target="_blank">GitHub</a>.',
|
||||
'adblocker_warning' => 'Conflitos entre o {site_name} e bloqueadores de anúncios podem causar tela branca. Use o modo anônimo ou desative a extensão.',
|
||||
'add_as_app' => 'Adicionar como Aplicativo',
|
||||
'add_as_app_description' => 'Instale o {site_name} como um aplicativo para compartilhar links rapidamente:',
|
||||
'add_as_app_step1' => 'No seu navegador, clique no ícone de menu (três pontos)',
|
||||
'add_as_app_step2' => 'Selecione "Instalar aplicativo" ou "Adicionar à tela inicial"',
|
||||
'add_as_app_step3' => 'Clique em "Instalar" para ter acesso rápido ao {site_name}',
|
||||
|
||||
'messages' => [
|
||||
'BLOCKED_DOMAIN' => [
|
||||
|
@ -52,4 +57,4 @@ return [
|
|||
'type' => 'warning'
|
||||
]
|
||||
]
|
||||
];
|
||||
];
|
||||
|
|
37
app/manifest.php
Normal file
37
app/manifest.php
Normal file
|
@ -0,0 +1,37 @@
|
|||
<?php
|
||||
require_once 'config.php';
|
||||
|
||||
header('Content-Type: application/json');
|
||||
|
||||
$manifest = [
|
||||
'name' => SITE_NAME,
|
||||
'short_name' => SITE_NAME,
|
||||
'description' => SITE_DESCRIPTION,
|
||||
'start_url' => SITE_URL,
|
||||
'display' => 'standalone',
|
||||
'background_color' => '#ffffff',
|
||||
'theme_color' => '#2563eb',
|
||||
'icons' => [
|
||||
[
|
||||
'src' => 'assets/pwa/192x192.png',
|
||||
'sizes' => '192x192',
|
||||
'type' => 'image/png',
|
||||
'purpose' => 'any maskable'
|
||||
],
|
||||
[
|
||||
'src' => 'assets/pwa/512x512.png',
|
||||
'sizes' => '512x512',
|
||||
'type' => 'image/png',
|
||||
'purpose' => 'any maskable'
|
||||
]
|
||||
],
|
||||
'share_target' => [
|
||||
'action' => '/p/',
|
||||
'method' => 'GET',
|
||||
'params' => [
|
||||
'url' => 'text'
|
||||
]
|
||||
]
|
||||
];
|
||||
|
||||
echo json_encode($manifest, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);
|
12
app/service-worker.js
Normal file
12
app/service-worker.js
Normal file
|
@ -0,0 +1,12 @@
|
|||
self.addEventListener('fetch', (event) => {
|
||||
event.respondWith(fetch(event.request));
|
||||
});
|
||||
|
||||
self.addEventListener('share_target', (event) => {
|
||||
event.respondWith((async () => {
|
||||
const formData = await event.request.formData();
|
||||
const url = formData.get('url') || '';
|
||||
const redirectUrl = `/p/${encodeURIComponent(url)}`;
|
||||
return Response.redirect(redirectUrl, 303);
|
||||
})());
|
||||
});
|
21
default.conf
21
default.conf
|
@ -7,32 +7,41 @@ server {
|
|||
|
||||
server_name _;
|
||||
|
||||
# Hide NGINX version to reduce exposed information
|
||||
# Oculta a versão do NGINX para reduzir informações expostas
|
||||
server_tokens off;
|
||||
|
||||
# Cabeçalhos de Segurança
|
||||
# Security Headers / Cabeçalhos de Segurança
|
||||
# Enable HSTS (HTTP Strict Transport Security) to force HTTPS connections
|
||||
# Habilita HSTS (HTTP Strict Transport Security) para forçar conexões HTTPS
|
||||
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
|
||||
|
||||
# Prevent clickjacking attacks by allowing the site to be displayed only in its own domain
|
||||
# Previne ataques de clickjacking, permitindo que o site seja exibido apenas em seu próprio domínio
|
||||
add_header X-Frame-Options "SAMEORIGIN" always;
|
||||
|
||||
# Enable protection against Cross-Site Scripting (XSS) attacks
|
||||
# Ativa proteção contra ataques de Cross-Site Scripting (XSS)
|
||||
add_header X-XSS-Protection "1; mode=block" always;
|
||||
|
||||
# Prevent browsers from MIME-type sniffing
|
||||
# Impede que navegadores tentem adivinhar (sniff) o tipo MIME dos arquivos
|
||||
add_header X-Content-Type-Options "nosniff" always;
|
||||
|
||||
# Control how referrer headers are sent
|
||||
# Controla como os cabeçalhos de referência são enviados
|
||||
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
|
||||
|
||||
# Limit upload size to prevent denial of service attacks
|
||||
# Limita o tamanho de uploads para prevenir ataques de negação de serviço
|
||||
client_max_body_size 10M;
|
||||
client_body_buffer_size 128k;
|
||||
|
||||
# Disable directory listing to prevent structure exposure
|
||||
# Desativa listagem de diretórios para evitar exposição de estrutura
|
||||
autoindex off;
|
||||
|
||||
# Block access to sensitive directories
|
||||
# Bloqueia acesso a diretórios sensíveis
|
||||
location ~ ^/(logs|cache|inc|data|cli)/ {
|
||||
return 301 /;
|
||||
|
@ -46,26 +55,36 @@ server {
|
|||
try_files $uri $uri/ /$1.php;
|
||||
}
|
||||
|
||||
# Serve manifest.json from manifest.php
|
||||
# Serve manifest.json a partir do manifest.php
|
||||
location = /manifest.json {
|
||||
rewrite ^ /manifest.php last;
|
||||
}
|
||||
|
||||
location ~ \.php$ {
|
||||
include snippets/fastcgi-php.conf;
|
||||
fastcgi_pass 127.0.0.1:9000;
|
||||
|
||||
# Hide header that reveals PHP version
|
||||
# Oculta cabeçalho que revela a versão do PHP
|
||||
fastcgi_hide_header X-Powered-By;
|
||||
}
|
||||
|
||||
# Block access to hidden files and directories
|
||||
# Bloqueia acesso a arquivos e diretórios ocultos
|
||||
location ~ /\. {
|
||||
deny all;
|
||||
return 404;
|
||||
}
|
||||
|
||||
# Block access to configuration and database files
|
||||
# Bloqueia acesso a arquivos de configuração e banco de dados
|
||||
location ~ \.(sql|conf|ini)$ {
|
||||
deny all;
|
||||
return 404;
|
||||
}
|
||||
|
||||
# Minimize logs to reduce information exposure
|
||||
# Minimiza logs para reduzir exposição de informações
|
||||
access_log /dev/null;
|
||||
error_log /dev/stderr warn;
|
||||
|
|
Loading…
Add table
Reference in a new issue