Skip to content
Open
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
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -163,3 +163,5 @@ cython_debug/

# Mac OS Files
.DS_Store

.nul
2 changes: 1 addition & 1 deletion frontend/package.json

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a tiny buxfix to ensure that npm run lint:fix is working properly.

Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
"start:testServer": "node scripts/testServer.js",
"lint": "npm run lint:code && npm run lint:style",
"lint:code": "eslint --ext ts,tsx src",
"lint:style": "stylelint --fix -f verbose src/**/*.scss",
"lint:style": "stylelint -f verbose src/**/*.scss",
"lint:fix": "npm run lint:code -- --fix && npm run lint:style -- --fix",
"start:local": "cross-env API_URL=http://localhost/ npm run start",
"prepare": "cd .. && husky frontend/.husky",
Expand Down
Binary file added frontend/public/assets/icons/icon-128x128.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 frontend/public/assets/icons/icon-144x144.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 frontend/public/assets/icons/icon-152x152.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 frontend/public/assets/icons/icon-192x192.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 frontend/public/assets/icons/icon-384x384.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 frontend/public/assets/icons/icon-512x512.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 frontend/public/assets/icons/icon-72x72.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 frontend/public/assets/icons/icon-96x96.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
11 changes: 9 additions & 2 deletions frontend/public/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,17 @@
<head>
<meta charset="utf-8"/>
<meta content="width=device-width, initial-scale=1" name="viewport"/>
<title>Qualibrate</title>
<meta name="description" content="QUAlibrate - Advanced Quantum System Calibration Platform"/>
<meta name="theme-color" content="#6272a4"/>
<meta name="mobile-web-app-capable" content="yes"/>
<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="QUAlibrate"/>
<title>QUAlibrate</title>

<link href="./assets/QM_Black_symbol_CMYK.svg" rel="shortcut icon"/>
<link href="./manifest.json" rel="manifest"/>
<link href="/manifest.json" rel="manifest"/>
<link href="./assets/icons/icon-192x192.png" rel="apple-touch-icon"/>
<style>
.token.operator {
background: transparent !important;
Expand Down
60 changes: 50 additions & 10 deletions frontend/public/manifest.json
Original file line number Diff line number Diff line change
@@ -1,17 +1,57 @@
{
"version": "0.4.0",
"manifest_version": 2,
"short_name": "QUAlibrate",
"name": "QUAlibrate",
"short_name": "QUAlibrate",
"description": "Web Interface for QUAlibrate - Advanced Quantum System Calibration",
"version": "0.4.0",
"start_url": "/",
"display": "standalone",
"orientation": "any",
"theme_color": "#2b2c32",
"background_color": "#ffffff",
"scope": "/",
"icons": [
{
"src": "favicon.png",
"sizes": "64x64 32x32 24x24 16x16",
"type": "image/x-icon"
"src": "/assets/icons/icon-72x72.png",
"sizes": "72x72",
"type": "image/png"
},
{
"src": "/assets/icons/icon-96x96.png",
"sizes": "96x96",
"type": "image/png"
},
{
"src": "/assets/icons/icon-128x128.png",
"sizes": "128x128",
"type": "image/png"
},
{
"src": "/assets/icons/icon-144x144.png",
"sizes": "144x144",
"type": "image/png"
},
{
"src": "/assets/icons/icon-152x152.png",
"sizes": "152x152",
"type": "image/png"
},
{
"src": "/assets/icons/icon-192x192.png",
"sizes": "192x192",
"type": "image/png"
},
{
"src": "/assets/icons/icon-384x384.png",
"sizes": "384x384",
"type": "image/png"
},
{
"src": "/assets/icons/icon-512x512.png",
"sizes": "512x512",
"type": "image/png"
}
],
"start_url": ".",
"display": "standalone",
"theme_color": "#000000",
"background_color": "#ffffff"
"categories": ["productivity", "utilities", "science"],
"lang": "en",
"dir": "ltr"
}
31 changes: 31 additions & 0 deletions frontend/public/service-worker.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// Basic Service Worker for QUAlibrate PWA
// Provides installability without offline functionality

const CACHE_NAME = 'qualibrate-basic-v4';

// Minimal service worker for PWA installability
self.addEventListener('install', (event) => {
console.log('[SW] Service worker installing for PWA installability');
// Skip waiting to activate immediately
self.skipWaiting();
});

self.addEventListener('activate', (event) => {
console.log('[SW] Service worker activated');
// Claim all clients immediately
event.waitUntil(self.clients.claim());
});

// Minimal fetch handler - just passes through all requests
self.addEventListener('fetch', (event) => {
// Let all requests go through to the network normally
// This ensures your app works exactly as before, just with PWA install capability
return;
});

// Handle messages from the main thread
self.addEventListener('message', (event) => {
if (event.data && event.data.type === 'SKIP_WAITING') {
self.skipWaiting();
}
});
13 changes: 13 additions & 0 deletions frontend/src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -57,3 +57,16 @@ if (container) {
</React.StrictMode>
);
}

// Register service worker for PWA functionality
if ("serviceWorker" in navigator) {
window.addEventListener("load", () => {
navigator.serviceWorker.register("/service-worker.js")
.then((registration) => {
console.log("SW registered: ", registration);
})
.catch((registrationError) => {
console.log("SW registration failed: ", registrationError);
});
});
}
55 changes: 55 additions & 0 deletions frontend/tools/convert-icons.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
const fs = require('fs');
const path = require('path');
const { spawn } = require('child_process');

// This script converts SVG icon to PNG format for PWA compatibility
// Usage: node convert-icons.js <path-to-svg-file>
const sizes = [72, 96, 128, 144, 152, 192, 384, 512];
const iconsDir = path.join(__dirname, '..', 'public', 'assets', 'icons');
const inputSvg = process.argv[2] || path.join(__dirname, '..', '..', '..', 'tmp', 'QM_white.svg');

// Ensure icons directory exists
if (!fs.existsSync(iconsDir)) {
fs.mkdirSync(iconsDir, { recursive: true });
}

async function convertSvgToPng(size) {
return new Promise((resolve, reject) => {
const pngPath = path.join(iconsDir, `icon-${size}x${size}.png`);

// Use ImageMagick convert to create PNG with specific size
const convert = spawn('magick', ['convert', inputSvg, '-resize', `${size}x${size}`, '-background', 'none', pngPath]);

convert.on('error', (err) => {
reject(new Error(`ImageMagick not found. Please install ImageMagick or use create-png-icons.html`));
});

convert.on('close', (code) => {
if (code === 0) {
console.log(`Created PNG icon: icon-${size}x${size}.png`);
resolve();
}
});
});
}

(async () => {
if (!fs.existsSync(inputSvg)) {
console.error(`Error: SVG file not found at ${inputSvg}`);
console.log('Usage: node convert-icons.js <path-to-svg-file>');
process.exit(1);
}

console.log(`Converting ${inputSvg} to PNG icons...`);

try {
for (const size of sizes) {
await convertSvgToPng(size);
}
console.log('\\nAll PNG icons created successfully!');
console.log('Icons saved to:', iconsDir);
} catch (error) {
console.error('Error creating icons:', error.message);
console.log('\\nAlternative: Open frontend/tools/create-png-icons.html in your browser');
}
})();
76 changes: 76 additions & 0 deletions frontend/tools/create-png-icons.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
<!DOCTYPE html>
<html>
<head>
<title>Generate PNG Icons</title>
<style>
body { font-family: Arial, sans-serif; padding: 20px; max-width: 600px; margin: 0 auto; }
input[type="file"] { margin: 20px 0; padding: 10px; border: 2px solid #2CCBE5; }
button { padding: 10px 20px; background: #2CCBE5; color: white; border: none; cursor: pointer; }
button:disabled { background: #ccc; cursor: not-allowed; }
</style>
</head>
<body>
<h1>Convert SVG to PNG Icons</h1>
<p>Select an SVG file to convert to multiple PNG sizes for PWA icons</p>
<input type="file" id="svgFile" accept=".svg">
<div id="status"></div>
<script>
const sizes = [72, 96, 128, 144, 152, 192, 384, 512];
const status = document.getElementById('status');
const fileInput = document.getElementById('svgFile');

fileInput.addEventListener('change', async (e) => {
const file = e.target.files[0];
if (!file) return;

const svgText = await file.text();
status.innerHTML = '<p>Starting conversion...</p>';

for (const size of sizes) {
await createPngIcon(svgText, size);
await new Promise(resolve => setTimeout(resolve, 500));
}
status.innerHTML += '<p><strong>✓ Done! Move all downloaded PNG files to frontend/public/assets/icons/</strong></p>';
});

async function createPngIcon(svgText, size) {
// Parse and modify SVG dimensions
const parser = new DOMParser();
const svgDoc = parser.parseFromString(svgText, 'image/svg+xml');
const svgElement = svgDoc.documentElement;

svgElement.setAttribute('width', size);
svgElement.setAttribute('height', size);

const svg = new XMLSerializer().serializeToString(svgElement);

// Create canvas
const canvas = document.createElement('canvas');
canvas.width = size;
canvas.height = size;
const ctx = canvas.getContext('2d');

// Create image from SVG
const img = new Image();
const svgBlob = new Blob([svg], { type: 'image/svg+xml;charset=utf-8' });
const url = URL.createObjectURL(svgBlob);

return new Promise((resolve) => {
img.onload = () => {
ctx.drawImage(img, 0, 0, size, size);
canvas.toBlob((blob) => {
const link = document.createElement('a');
link.download = `icon-${size}x${size}.png`;
link.href = URL.createObjectURL(blob);
link.click();
status.innerHTML += `<p>✓ Created icon-${size}x${size}.png</p>`;
URL.revokeObjectURL(url);
resolve();
}, 'image/png');
};
img.src = url;
});
}
</script>
</body>
</html>
11 changes: 10 additions & 1 deletion frontend/webpack.dev.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,12 @@ const config = {
},
},
devServer: {
static: false,
static: [
{
directory: inProject("public"),
publicPath: "/",
},
],
port: 1234,
hot: true,
historyApiFallback: true,
Expand All @@ -61,6 +66,10 @@ const config = {
from: inProject("public/manifest.json"),
to: inProject("dist/manifest.json"),
},
{
from: inProject("public/service-worker.js"),
to: inProject("dist/service-worker.js"),
},
],
}),
new MiniCssExtractPlugin({
Expand Down
4 changes: 4 additions & 0 deletions frontend/webpack.prod.js
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,10 @@ const config = {
from: inProject("public/manifest.json"),
to: inProject("dist/manifest.json"),
},
{
from: inProject("public/service-worker.js"),
to: inProject("dist/service-worker.js"),
},
],
}),
new MiniCssExtractPlugin({
Expand Down
Loading