Skip to content

Feature: Extract inline assets #18

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 14 commits into from
Feb 24, 2025
Merged
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
10 changes: 10 additions & 0 deletions .github/workflows/pr.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -113,3 +113,13 @@ jobs:
docker compose run --rm phpfpm composer install
docker compose run --rm phpfpm bin/console api:openapi:export --yaml --output=public/spec.yaml --no-interaction
git diff --diff-filter=ACMRT --exit-code public/spec.yaml

composer-audit:
name: Run composer audit
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: |
docker network create frontend
docker compose run --rm phpfpm composer install
docker compose run --rm phpfpm composer audit
7 changes: 7 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,10 @@ phpstan.neon

# Ignore package-lock.json
package-lock.json

###> symfony/webpack-encore-bundle ###
/node_modules/
/public/build/
npm-debug.log
yarn-error.log
###< symfony/webpack-encore-bundle ###
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ See [keep a changelog] for information about writing changes to this log.

## [Unreleased]

[PR-18](https://github.com/itk-dev/itqr/pull/18)
- Extract inline assets
- Improve download preview to serve multiple reviews
[PR-17](https://github.com/itk-dev/itqr/pull/17)
- Cleanup github actions, Standardize on using docker compose
[PR-14](https://github.com/itk-dev/itqr/pull/14)
Expand Down
104 changes: 104 additions & 0 deletions assets/app.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
import './styles/app.css';

document.addEventListener('DOMContentLoaded', () => {
const qrCodeContainer = document.getElementById('qrCodeContainer');
const tabsContainer = document.getElementById('qrCodeTabs'); // Navigation tabs
const tabContentContainer = document.getElementById('qrCodeTabContent'); // Tab content
const form = document.querySelector('.form-wrapper form');
const selectedQrCodes = document.getElementById('selectedQrCodes');

// Ensure all containers and elements exist
if (!qrCodeContainer || !tabsContainer || !tabContentContainer || !form) {
console.error('Required elements not found!');
return;
}

const generateQrPath = qrCodeContainer.dataset.generateQrPath;

if (!generateQrPath) {
console.error('QR Code generate path is missing! Add the "data-generate-qr-path" attribute.');
return;
}

async function updateQRCode() {
// Clear tab and content containers
tabsContainer.innerHTML = '';
tabContentContainer.innerHTML = '';

// Prepare form data for POST request
const formData = new FormData(form);
formData.append('selectedQrCodes', selectedQrCodes.value);

try {
// Fetch the QR codes from the endpoint
const response = await fetch(generateQrPath, {
method: 'POST',
body: formData,
});

if (response.ok) {
const data = await response.json();
const qrCodes = data.qrCodes; // Array of qr titles and generated base64 images

if (typeof qrCodes === 'object') {
// Loop through all images and create tabs dynamically
Object.entries(qrCodes).forEach(([title, imageSrc]) => {
// Sanitize the title to create valid IDs
const sanitizedTitle = title.replace(/[^a-zA-Z0-9-_]/g, '_');

// Create a unique tab ID
const tabId = `qrCodeTab-${sanitizedTitle}`;
const tabPaneId = `qrCodeContent-${sanitizedTitle}`;

// Create tab navigation item
const tabItem = document.createElement('li');
tabItem.className = 'nav-item';
tabItem.role = 'presentation';
tabItem.innerHTML = `
<button class="nav-link ${tabsContainer.children.length === 0 ? 'active' : ''}"
id="${tabId}"
data-bs-toggle="tab"
data-bs-target="#${tabPaneId}"
type="button"
role="tab"
aria-controls="${tabPaneId}"
aria-selected="${tabsContainer.children.length === 0}">
${title}
</button>
`;
tabsContainer.appendChild(tabItem);

// Create tab content (image)
const tabContent = document.createElement('div');
tabContent.className = `tab-pane fade ${tabsContainer.children.length === 1 ? 'show active' : ''} qr-code-tab-pane`;
tabContent.id = tabPaneId;
tabContent.role = 'tabpanel';
tabContent.innerHTML = `
<img src="${imageSrc}" alt="QR Code titled ${title}" class="qr-code-image">
`;
tabContentContainer.appendChild(tabContent);
});
} else {
console.error('Invalid data format. Expected an array of QR code images.');
}
} else {
console.error('Failed to fetch QR codes. Status:', response.status);
}
} catch (error) {
console.error('Error while fetching QR codes:', error);
}
}

// Timeout before updating qr code after typing
let typingTimer;

form.addEventListener('input', () => {
clearTimeout(typingTimer);

typingTimer = setTimeout(() => {
updateQRCode();
}, 500);
});

updateQRCode();
});
72 changes: 72 additions & 0 deletions assets/styles/app.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@

.qr-preview h3 {
margin-bottom: 10px;
}

.form-wrapper {
display: flex;
}

.form-wrapper form {
flex: 1;
padding-right: 30px;
}

.popover-link {
position: relative;
display: inline-block;
text-decoration: underline;
}

.popover-content {
display: none;
position: absolute;
top: 120%;
left: 50%;
transform: translateX(-50%);
background-color: white;
border: 1px solid #ccc;
border-radius: 5px;
box-shadow: 0px 4px 8px rgba(0, 0, 0, 0.1);
padding: 5px;
z-index: 1000;
white-space: nowrap;
}

.popover-content img {
max-width: 200px;
max-height: 200px;
}

.popover-link:hover .popover-content {
display: block;
}


.qr-preview {
display: flex;
flex-direction: column;
border: 1px solid #ddd;
border-radius: 6px;
background-color: #f9f9f9;
flex: 1;
height: 475px;

.nav-link {
color: #000;
}
.nav-link.active {
color: #000;
font-weight: bold;
}
}

.qr-preview .qr-code-tab-pane {
text-align: center;
}

.qr-preview .qr-code-image {
max-width: 100%;
display: block;
margin: 15px auto 0 auto;
}
4 changes: 3 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,9 @@
"symfony/maker-bundle": "^1.62.1",
"symfony/runtime": "~7.2.0",
"symfony/twig-bundle": "~7.2.0",
"symfony/yaml": "~7.2.0"
"symfony/webpack-encore-bundle": "^2.2",
"symfony/yaml": "~7.2.0",
"twig/twig": "^3.19.0"
},
"require-dev": {
"doctrine/doctrine-fixtures-bundle": "^4.0",
Expand Down
Loading