mirror of
https://github.com/Frooodle/Stirling-PDF.git
synced 2026-04-22 23:08:53 +02:00
Delete code from invalid license (#5947)
This commit is contained in:
@@ -1,80 +0,0 @@
|
||||
package stirling.software.SPDF.controller.api;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
import org.apache.pdfbox.pdmodel.PDDocument;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.ModelAttribute;
|
||||
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import stirling.software.SPDF.config.swagger.StandardPdfResponse;
|
||||
import stirling.software.SPDF.service.PdfImageRemovalService;
|
||||
import stirling.software.common.annotations.AutoJobPostMapping;
|
||||
import stirling.software.common.annotations.api.GeneralApi;
|
||||
import stirling.software.common.model.api.PDFFile;
|
||||
import stirling.software.common.service.CustomPDFDocumentFactory;
|
||||
import stirling.software.common.util.GeneralUtils;
|
||||
import stirling.software.common.util.WebResponseUtils;
|
||||
|
||||
/**
|
||||
* Controller class for handling PDF image removal requests. Provides an endpoint to remove images
|
||||
* from a PDF file to reduce its size.
|
||||
*/
|
||||
@GeneralApi
|
||||
@RequiredArgsConstructor
|
||||
public class PdfImageRemovalController {
|
||||
|
||||
// Service for removing images from PDFs
|
||||
private final PdfImageRemovalService pdfImageRemovalService;
|
||||
|
||||
private final CustomPDFDocumentFactory pdfDocumentFactory;
|
||||
|
||||
/**
|
||||
* Endpoint to remove images from a PDF file.
|
||||
*
|
||||
* <p>This method processes the uploaded PDF file, removes all images, and returns the modified
|
||||
* PDF file with a new name indicating that images were removed.
|
||||
*
|
||||
* @param file The PDF file with images to be removed.
|
||||
* @return ResponseEntity containing the modified PDF file as byte array with appropriate
|
||||
* content type and filename.
|
||||
* @throws IOException If an error occurs while processing the PDF file.
|
||||
*/
|
||||
@AutoJobPostMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE, value = "/remove-image-pdf")
|
||||
@StandardPdfResponse
|
||||
@Operation(
|
||||
summary = "Remove images from file to reduce the file size.",
|
||||
description =
|
||||
"This endpoint remove images from file to reduce the file size.Input:PDF"
|
||||
+ " Output:PDF Type:SISO")
|
||||
public ResponseEntity<byte[]> removeImages(@ModelAttribute PDFFile file) throws IOException {
|
||||
// Load the PDF document with proper resource management
|
||||
try (PDDocument document = pdfDocumentFactory.load(file)) {
|
||||
|
||||
// Remove images from the PDF document using the service
|
||||
try (PDDocument modifiedDocument =
|
||||
pdfImageRemovalService.removeImagesFromPdf(document)) {
|
||||
|
||||
// Create a ByteArrayOutputStream to hold the modified PDF data
|
||||
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
||||
|
||||
// Save the modified PDF document to the output stream
|
||||
modifiedDocument.save(outputStream);
|
||||
|
||||
// Generate a new filename for the modified PDF
|
||||
String mergedFileName =
|
||||
GeneralUtils.generateFilename(
|
||||
file.getFileInput().getOriginalFilename(), "_images_removed.pdf");
|
||||
|
||||
// Convert the byte array to a web response and return it
|
||||
return WebResponseUtils.bytesToWebResponse(
|
||||
outputStream.toByteArray(), mergedFileName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -150,28 +150,6 @@ public class RearrangePagesPDFController {
|
||||
return newPageOrder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Rearrange pages in a PDF file by merging odd and even pages. The first half of the pages will
|
||||
* be the odd pages, and the second half will be the even pages as input. <br>
|
||||
* This method is visible for testing purposes only.
|
||||
*
|
||||
* @param totalPages Total number of pages in the PDF file.
|
||||
* @return List of page numbers in the new order. The first page is 0.
|
||||
*/
|
||||
List<Integer> oddEvenMerge(int totalPages) {
|
||||
List<Integer> newPageOrderZeroBased = new ArrayList<>();
|
||||
int numberOfOddPages = (totalPages + 1) / 2;
|
||||
|
||||
for (int oneBasedIndex = 1; oneBasedIndex < (numberOfOddPages + 1); oneBasedIndex++) {
|
||||
newPageOrderZeroBased.add((oneBasedIndex - 1));
|
||||
if (numberOfOddPages + oneBasedIndex <= totalPages) {
|
||||
newPageOrderZeroBased.add((numberOfOddPages + oneBasedIndex - 1));
|
||||
}
|
||||
}
|
||||
|
||||
return newPageOrderZeroBased;
|
||||
}
|
||||
|
||||
private List<Integer> duplicate(int totalPages, String pageOrder) {
|
||||
List<Integer> newPageOrder = new ArrayList<>();
|
||||
int duplicateCount;
|
||||
@@ -220,7 +198,6 @@ public class RearrangePagesPDFController {
|
||||
case BOOKLET_SORT -> bookletSort(totalPages);
|
||||
case SIDE_STITCH_BOOKLET_SORT -> sideStitchBooklet(totalPages);
|
||||
case ODD_EVEN_SPLIT -> oddEvenSplit(totalPages);
|
||||
case ODD_EVEN_MERGE -> oddEvenMerge(totalPages);
|
||||
case REMOVE_FIRST -> removeFirst(totalPages);
|
||||
case REMOVE_LAST -> removeLast(totalPages);
|
||||
case REMOVE_FIRST_AND_LAST -> removeFirstAndLast(totalPages);
|
||||
|
||||
@@ -1,20 +1,14 @@
|
||||
package stirling.software.SPDF.controller.api.misc;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.Image;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.awt.image.RenderedImage;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.zip.Deflater;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipOutputStream;
|
||||
@@ -43,7 +37,6 @@ import stirling.software.common.annotations.api.MiscApi;
|
||||
import stirling.software.common.service.CustomPDFDocumentFactory;
|
||||
import stirling.software.common.util.ExceptionUtils;
|
||||
import stirling.software.common.util.GeneralUtils;
|
||||
import stirling.software.common.util.ImageProcessingUtils;
|
||||
import stirling.software.common.util.TempFile;
|
||||
import stirling.software.common.util.TempFileManager;
|
||||
import stirling.software.common.util.WebResponseUtils;
|
||||
@@ -65,203 +58,97 @@ public class ExtractImagesController {
|
||||
+ " file. Users can specify the output image format. Input:PDF"
|
||||
+ " Output:IMAGE/ZIP Type:SIMO")
|
||||
public ResponseEntity<StreamingResponseBody> extractImages(
|
||||
@ModelAttribute PDFExtractImagesRequest request)
|
||||
throws IOException, InterruptedException, ExecutionException {
|
||||
@ModelAttribute PDFExtractImagesRequest request) throws IOException {
|
||||
MultipartFile file = request.getFileInput();
|
||||
String format = request.getFormat();
|
||||
boolean allowDuplicates = Boolean.TRUE.equals(request.getAllowDuplicates());
|
||||
String imageFormat = request.getFormat();
|
||||
|
||||
String filename = GeneralUtils.removeExtension(file.getOriginalFilename());
|
||||
Set<byte[]> processedImages = new HashSet<>();
|
||||
String baseFilename = GeneralUtils.removeExtension(file.getOriginalFilename());
|
||||
Set<Integer> processedImageHashes = new HashSet<>();
|
||||
|
||||
TempFile zipTempFile = new TempFile(tempFileManager, ".zip");
|
||||
try (ZipOutputStream zos =
|
||||
new ZipOutputStream(Files.newOutputStream(zipTempFile.getPath()));
|
||||
PDDocument document = pdfDocumentFactory.load(file)) {
|
||||
TempFile zipFile = new TempFile(tempFileManager, ".zip");
|
||||
try (ZipOutputStream zipStream = new ZipOutputStream(Files.newOutputStream(zipFile.getPath()));
|
||||
PDDocument pdfDoc = pdfDocumentFactory.load(file)) {
|
||||
|
||||
// Set compression level
|
||||
zos.setLevel(Deflater.BEST_COMPRESSION);
|
||||
zipStream.setLevel(Deflater.BEST_COMPRESSION);
|
||||
|
||||
// Determine if multithreading should be used based on PDF size or number of pages
|
||||
boolean useMultithreading = shouldUseMultithreading(file, document);
|
||||
|
||||
if (useMultithreading) {
|
||||
ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor();
|
||||
Set<Future<Void>> futures = new HashSet<>();
|
||||
|
||||
try {
|
||||
int pageCount = document.getPages().getCount();
|
||||
log.debug("Document reports {} pages", pageCount);
|
||||
|
||||
int consecutiveFailures = 0;
|
||||
|
||||
for (int pgNum = 0; pgNum < pageCount; pgNum++) {
|
||||
try {
|
||||
PDPage page = document.getPage(pgNum);
|
||||
consecutiveFailures = 0; // Reset on success
|
||||
final int currentPageNum =
|
||||
pgNum + 1; // Convert to 1-based page numbering
|
||||
Future<Void> future =
|
||||
executor.submit(
|
||||
() -> {
|
||||
try {
|
||||
// Call the image extraction method for each
|
||||
// page
|
||||
extractImagesFromPage(
|
||||
page,
|
||||
format,
|
||||
filename,
|
||||
currentPageNum,
|
||||
processedImages,
|
||||
zos,
|
||||
allowDuplicates);
|
||||
} catch (Exception e) {
|
||||
// Log the error and continue processing other
|
||||
// pages
|
||||
ExceptionUtils.logException(
|
||||
"image extraction from page "
|
||||
+ currentPageNum,
|
||||
e);
|
||||
}
|
||||
|
||||
return null; // Callable requires a return type
|
||||
});
|
||||
|
||||
// Add the Future object to the list to track completion
|
||||
futures.add(future);
|
||||
} catch (Exception e) {
|
||||
consecutiveFailures++;
|
||||
ExceptionUtils.logException("page access for page " + (pgNum + 1), e);
|
||||
|
||||
if (consecutiveFailures >= 3) {
|
||||
log.warn("Stopping page iteration after 3 consecutive failures");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
ExceptionUtils.logException("page count determination", e);
|
||||
throw e;
|
||||
}
|
||||
|
||||
// Wait for all tasks to complete
|
||||
for (Future<Void> future : futures) {
|
||||
future.get();
|
||||
}
|
||||
|
||||
// Close executor service
|
||||
executor.shutdown();
|
||||
} else {
|
||||
// Single-threaded extraction
|
||||
for (int pgNum = 0; pgNum < document.getPages().getCount(); pgNum++) {
|
||||
PDPage page = document.getPage(pgNum);
|
||||
extractImagesFromPage(
|
||||
page,
|
||||
format,
|
||||
filename,
|
||||
pgNum + 1,
|
||||
processedImages,
|
||||
zos,
|
||||
allowDuplicates);
|
||||
}
|
||||
int totalPages = pdfDoc.getNumberOfPages();
|
||||
for (int pageIndex = 0; pageIndex < totalPages; pageIndex++) {
|
||||
PDPage currentPage = pdfDoc.getPage(pageIndex);
|
||||
extractAndAddImagesToZip(
|
||||
currentPage, imageFormat, baseFilename, pageIndex + 1,
|
||||
processedImageHashes, zipStream);
|
||||
}
|
||||
// document and zos closed by try-with-resources
|
||||
} catch (Exception e) {
|
||||
zipTempFile.close();
|
||||
zipFile.close();
|
||||
throw e;
|
||||
}
|
||||
|
||||
return WebResponseUtils.zipFileToWebResponse(
|
||||
zipTempFile, filename + "_extracted-images.zip");
|
||||
zipFile, baseFilename + "_extracted-images.zip");
|
||||
}
|
||||
|
||||
private boolean shouldUseMultithreading(MultipartFile file, PDDocument document) {
|
||||
// Criteria: Use multithreading if file size > 10MB or number of pages > 20
|
||||
long fileSizeInMB = file.getSize() / (1024 * 1024);
|
||||
int numberOfPages = document.getPages().getCount();
|
||||
return fileSizeInMB > 10 || numberOfPages > 20;
|
||||
}
|
||||
|
||||
private void extractImagesFromPage(
|
||||
private void extractAndAddImagesToZip(
|
||||
PDPage page,
|
||||
String format,
|
||||
String filename,
|
||||
int pageNum,
|
||||
Set<byte[]> processedImages,
|
||||
ZipOutputStream zos,
|
||||
boolean allowDuplicates)
|
||||
String imageFormat,
|
||||
String baseFilename,
|
||||
int pageNumber,
|
||||
Set<Integer> seenImageHashes,
|
||||
ZipOutputStream zipOutput)
|
||||
throws IOException {
|
||||
MessageDigest md;
|
||||
try {
|
||||
md = MessageDigest.getInstance("MD5");
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
log.error("MD5 algorithm not available for extractImages hash.", e);
|
||||
return;
|
||||
}
|
||||
if (page.getResources() == null || page.getResources().getXObjectNames() == null) {
|
||||
return;
|
||||
}
|
||||
int count = 1;
|
||||
for (COSName name : page.getResources().getXObjectNames()) {
|
||||
|
||||
int imageCount = 1;
|
||||
for (COSName resourceName : page.getResources().getXObjectNames()) {
|
||||
if (!page.getResources().isImageXObject(resourceName)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
if (page.getResources().isImageXObject(name)) {
|
||||
PDImageXObject image = (PDImageXObject) page.getResources().getXObject(name);
|
||||
if (!allowDuplicates) {
|
||||
byte[] data = ImageProcessingUtils.getImageData(image.getImage());
|
||||
byte[] imageHash = md.digest(data);
|
||||
synchronized (processedImages) {
|
||||
if (processedImages.stream()
|
||||
.anyMatch(hash -> Arrays.equals(hash, imageHash))) {
|
||||
continue; // Skip already processed images
|
||||
}
|
||||
processedImages.add(imageHash);
|
||||
}
|
||||
}
|
||||
PDImageXObject imageObject =
|
||||
(PDImageXObject) page.getResources().getXObject(resourceName);
|
||||
int imageHashCode = imageObject.hashCode();
|
||||
|
||||
RenderedImage renderedImage = image.getImage();
|
||||
|
||||
// Convert to standard RGB colorspace if needed
|
||||
BufferedImage bufferedImage = convertToRGB(renderedImage, format);
|
||||
|
||||
// Encode image outside the lock to allow parallel encoding across threads
|
||||
String imageName = filename + "_page_" + pageNum + "_" + count++ + "." + format;
|
||||
ByteArrayOutputStream imageBaos = new ByteArrayOutputStream();
|
||||
ImageIO.write(bufferedImage, format, imageBaos);
|
||||
byte[] imageData = imageBaos.toByteArray();
|
||||
|
||||
// Write encoded bytes to zip under lock (ZipOutputStream requires
|
||||
// serialization)
|
||||
synchronized (zos) {
|
||||
zos.putNextEntry(new ZipEntry(imageName));
|
||||
zos.write(imageData);
|
||||
zos.closeEntry();
|
||||
}
|
||||
if (seenImageHashes.contains(imageHashCode)) {
|
||||
continue;
|
||||
}
|
||||
seenImageHashes.add(imageHashCode);
|
||||
|
||||
RenderedImage sourceImage = imageObject.getImage();
|
||||
BufferedImage convertedImage = convertImageToFormat(sourceImage, imageFormat);
|
||||
|
||||
String imagePath =
|
||||
baseFilename + "_page_" + pageNumber + "_" + imageCount++ + "."
|
||||
+ imageFormat;
|
||||
ByteArrayOutputStream imageBuffer = new ByteArrayOutputStream();
|
||||
ImageIO.write(convertedImage, imageFormat, imageBuffer);
|
||||
|
||||
zipOutput.putNextEntry(new ZipEntry(imagePath));
|
||||
zipOutput.write(imageBuffer.toByteArray());
|
||||
zipOutput.closeEntry();
|
||||
|
||||
} catch (IOException e) {
|
||||
ExceptionUtils.logException("image extraction", e);
|
||||
ExceptionUtils.logException("image extraction failed", e);
|
||||
throw ExceptionUtils.handlePdfException(e, "during image extraction");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private BufferedImage convertToRGB(RenderedImage renderedImage, String format) {
|
||||
int width = renderedImage.getWidth();
|
||||
int height = renderedImage.getHeight();
|
||||
BufferedImage rgbImage;
|
||||
private BufferedImage convertImageToFormat(RenderedImage source, String format) {
|
||||
int width = source.getWidth();
|
||||
int height = source.getHeight();
|
||||
|
||||
int imageType = BufferedImage.TYPE_INT_RGB;
|
||||
if ("png".equalsIgnoreCase(format)) {
|
||||
rgbImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
|
||||
} else if ("jpeg".equalsIgnoreCase(format) || "jpg".equalsIgnoreCase(format)) {
|
||||
rgbImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
|
||||
} else if ("gif".equalsIgnoreCase(format)) {
|
||||
rgbImage = new BufferedImage(width, height, BufferedImage.TYPE_BYTE_INDEXED);
|
||||
} else {
|
||||
rgbImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
|
||||
imageType = BufferedImage.TYPE_INT_ARGB;
|
||||
}
|
||||
|
||||
Graphics2D g = rgbImage.createGraphics();
|
||||
g.drawImage((Image) renderedImage, 0, 0, null);
|
||||
g.dispose();
|
||||
return rgbImage;
|
||||
BufferedImage result = new BufferedImage(width, height, imageType);
|
||||
Graphics2D graphics = result.createGraphics();
|
||||
graphics.drawImage((Image) source, 0, 0, null);
|
||||
graphics.dispose();
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,7 +36,6 @@ import stirling.software.SPDF.model.PipelineResult;
|
||||
import stirling.software.SPDF.service.ApiDocService;
|
||||
import stirling.software.common.configuration.RuntimePathConfig;
|
||||
import stirling.software.common.service.PostHogService;
|
||||
import stirling.software.common.util.FileMonitor;
|
||||
|
||||
import tools.jackson.databind.ObjectMapper;
|
||||
|
||||
@@ -50,7 +49,6 @@ public class PipelineDirectoryProcessor {
|
||||
private final ObjectMapper objectMapper;
|
||||
private final ApiDocService apiDocService;
|
||||
private final PipelineProcessor processor;
|
||||
private final FileMonitor fileMonitor;
|
||||
private final PostHogService postHogService;
|
||||
private final List<String> watchedFoldersDirs;
|
||||
private final String finishedFoldersDir;
|
||||
@@ -63,13 +61,11 @@ public class PipelineDirectoryProcessor {
|
||||
ObjectMapper objectMapper,
|
||||
ApiDocService apiDocService,
|
||||
PipelineProcessor processor,
|
||||
FileMonitor fileMonitor,
|
||||
PostHogService postHogService,
|
||||
RuntimePathConfig runtimePathConfig) {
|
||||
this.objectMapper = objectMapper;
|
||||
this.apiDocService = apiDocService;
|
||||
this.processor = processor;
|
||||
this.fileMonitor = fileMonitor;
|
||||
this.postHogService = postHogService;
|
||||
this.watchedFoldersDirs = runtimePathConfig.getPipelineWatchedFoldersPaths();
|
||||
this.finishedFoldersDir = runtimePathConfig.getPipelineFinishedFoldersPath();
|
||||
@@ -274,18 +270,7 @@ public class PipelineDirectoryProcessor {
|
||||
return isAllowed;
|
||||
})
|
||||
.map(Path::toAbsolutePath)
|
||||
.filter(
|
||||
path -> {
|
||||
boolean isReady =
|
||||
fileMonitor.isFileReadyForProcessing(path);
|
||||
if (!isReady) {
|
||||
log.info(
|
||||
"File not ready for processing (locked/created"
|
||||
+ " last 5s): {}",
|
||||
path);
|
||||
}
|
||||
return isReady;
|
||||
})
|
||||
.filter(path -> true)
|
||||
.map(Path::toFile)
|
||||
.toArray(File[]::new);
|
||||
log.info(
|
||||
|
||||
@@ -7,7 +7,6 @@ public enum SortTypes {
|
||||
BOOKLET_SORT,
|
||||
SIDE_STITCH_BOOKLET_SORT,
|
||||
ODD_EVEN_SPLIT,
|
||||
ODD_EVEN_MERGE,
|
||||
REMOVE_FIRST,
|
||||
REMOVE_LAST,
|
||||
REMOVE_FIRST_AND_LAST,
|
||||
|
||||
@@ -22,7 +22,6 @@ public class RearrangePagesRequest extends PDFWithPageNums {
|
||||
+ "DUPLEX_SORT: Sorts pages as if all fronts were scanned then all backs in reverse (1, n, 2, n-1, ...). "
|
||||
+ "BOOKLET_SORT: Arranges pages for booklet printing (last, first, second, second last, ...).\n"
|
||||
+ "ODD_EVEN_SPLIT: Splits and arranges pages into odd and even numbered pages.\n"
|
||||
+ "ODD_EVEN_MERGE: Merges pages and organises them alternately into odd and even pages.\n"
|
||||
+ "REMOVE_FIRST: Removes the first page.\n"
|
||||
+ "REMOVE_LAST: Removes the last page.\n"
|
||||
+ "REMOVE_FIRST_AND_LAST: Removes both the first and the last pages.\n")
|
||||
|
||||
@@ -1,51 +0,0 @@
|
||||
package stirling.software.SPDF.service;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.pdfbox.cos.COSName;
|
||||
import org.apache.pdfbox.pdmodel.PDDocument;
|
||||
import org.apache.pdfbox.pdmodel.PDPage;
|
||||
import org.apache.pdfbox.pdmodel.PDResources;
|
||||
import org.apache.pdfbox.pdmodel.graphics.PDXObject;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/** Service class responsible for removing image objects from a PDF document. */
|
||||
@Service
|
||||
public class PdfImageRemovalService {
|
||||
|
||||
/**
|
||||
* Removes all image objects from the provided PDF document.
|
||||
*
|
||||
* <p>This method iterates over each page in the document and removes any image XObjects found
|
||||
* in the page's resources.
|
||||
*
|
||||
* @param document The PDF document from which images will be removed.
|
||||
* @return The modified PDF document with images removed.
|
||||
* @throws IOException If an error occurs while processing the PDF document.
|
||||
*/
|
||||
public PDDocument removeImagesFromPdf(PDDocument document) throws IOException {
|
||||
// Iterate over each page in the PDF document
|
||||
for (PDPage page : document.getPages()) {
|
||||
PDResources resources = page.getResources();
|
||||
// Collect the XObject names to remove
|
||||
List<COSName> namesToRemove = new ArrayList<>();
|
||||
|
||||
// Iterate over all XObject names in the page's resources
|
||||
for (COSName name : resources.getXObjectNames()) {
|
||||
// Check if the XObject is an image
|
||||
if (resources.isImageXObject(name)) {
|
||||
// Collect the name for removal
|
||||
namesToRemove.add(name);
|
||||
}
|
||||
}
|
||||
|
||||
// Now, modify the resources by removing the collected names
|
||||
for (COSName name : namesToRemove) {
|
||||
resources.put(name, (PDXObject) null);
|
||||
}
|
||||
}
|
||||
return document;
|
||||
}
|
||||
}
|
||||
@@ -1,111 +0,0 @@
|
||||
#searchBar {
|
||||
color: var(--md-sys-color-on-surface);
|
||||
background-color: var(--md-sys-color-surface-container-low);
|
||||
width: 100%;
|
||||
font-size: 16px;
|
||||
margin-bottom: 2rem;
|
||||
padding: 0.75rem 3.5rem;
|
||||
border: 1px solid var(--md-sys-color-outline-variant);
|
||||
border-radius: 3rem;
|
||||
outline-color: var(--md-sys-color-outline-variant);
|
||||
}
|
||||
|
||||
#filtersContainer {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.filter-button {
|
||||
color: var(--md-sys-color-secondary);
|
||||
user-select: none;
|
||||
cursor: pointer;
|
||||
transition: transform 0.3s;
|
||||
transform-origin: center center;
|
||||
}
|
||||
|
||||
.filter-button:hover {
|
||||
transform: scale(1.08);
|
||||
}
|
||||
|
||||
.search-icon {
|
||||
position: absolute;
|
||||
margin: 0.75rem 1rem;
|
||||
border: 0.1rem solid transparent;
|
||||
}
|
||||
|
||||
.favorite-icon {
|
||||
display: none;
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
right: 10px;
|
||||
color: var(--md-sys-color-secondary);
|
||||
}
|
||||
|
||||
#tool-icon {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
#tool-text {
|
||||
margin: 0.0rem 0 0 1.25rem;
|
||||
}
|
||||
|
||||
.favorite-icon img {
|
||||
filter: brightness(0) invert(var(--md-theme-filter-color));
|
||||
}
|
||||
|
||||
.favorite-icon:hover .material-symbols-rounded {
|
||||
transform: scale(1.2);
|
||||
}
|
||||
|
||||
.favorite-icon .material-symbols-rounded.fill{
|
||||
color: #f5c000;
|
||||
}
|
||||
|
||||
.jumbotron {
|
||||
padding: 3rem 3rem;
|
||||
/* Reduce vertical padding */
|
||||
}
|
||||
|
||||
.lookatme {
|
||||
opacity: 1;
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.lookatme::after {
|
||||
color: #e33100;
|
||||
text-shadow: 0 0 5px #e33100;
|
||||
/* in the html, the data-lookatme-text attribute must */
|
||||
/* contain the same text as the .lookatme element */
|
||||
content: attr(data-lookatme-text);
|
||||
padding: inherit;
|
||||
position: absolute;
|
||||
inset: 0 0 0 0;
|
||||
z-index: 1;
|
||||
/* 20 steps / 2 seconds = 10fps */
|
||||
-webkit-animation: 2s infinite Pulse steps(20);
|
||||
animation: 2s infinite Pulse steps(20);
|
||||
}
|
||||
|
||||
.newfeature{
|
||||
display: flex;
|
||||
width:fit-content
|
||||
}
|
||||
.recent-features{
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
max-width: 100%;
|
||||
overflow: hidden;
|
||||
justify-content: center;
|
||||
|
||||
}
|
||||
|
||||
.close-icon {
|
||||
color: var(--favourite-remove) !important;
|
||||
}
|
||||
.add-icon {
|
||||
color: var(--favourite-add) !important;
|
||||
}
|
||||
@@ -1,625 +0,0 @@
|
||||
/* Base Container Styles */
|
||||
.multi-tool-container {
|
||||
max-width: 100vw;
|
||||
margin: 0;
|
||||
padding: 0 20px;
|
||||
}
|
||||
|
||||
/* Form Elements */
|
||||
label {
|
||||
text-align: left;
|
||||
display: block;
|
||||
padding: 0rem 0.25rem;
|
||||
font-size: 1.25rem;
|
||||
}
|
||||
|
||||
.form-control {
|
||||
border-radius: 16px !important;
|
||||
padding: 0.75rem;
|
||||
border: 1px solid var(--theme-color-outline-variant);
|
||||
flex-grow: 5;
|
||||
}
|
||||
|
||||
/* Action Bar Styles */
|
||||
.mt-action-bar {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
align-items: start;
|
||||
border: none;
|
||||
backdrop-filter: blur(2px);
|
||||
top: 10px;
|
||||
z-index: 11;
|
||||
padding: 1.25rem;
|
||||
border-radius: 2rem;
|
||||
margin: 0px 25px;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.mt-action-bar > * {
|
||||
padding-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.mt-file-uploader {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.mt-action-bar svg,
|
||||
.mt-action-btn svg {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
}
|
||||
|
||||
.mt-action-bar .mt-filename {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
/* Action Button Styles */
|
||||
.mt-action-btn {
|
||||
position: fixed;
|
||||
bottom: 80px;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
border-radius: 2rem;
|
||||
z-index: 12;
|
||||
background-color: var(--md-sys-color-surface-container-low);
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
width: fit-content;
|
||||
justify-content: center;
|
||||
padding: 10px 20px;
|
||||
transition: all 0.3s ease-in-out;
|
||||
}
|
||||
|
||||
.mt-action-btn .btn {
|
||||
width: 3.5rem;
|
||||
height: 3.5rem;
|
||||
border-radius: 20px;
|
||||
padding: 0;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
/* Card and Container Styles */
|
||||
.bg-card {
|
||||
background-color: var(--md-sys-color-surface-5);
|
||||
border-radius: 3rem;
|
||||
padding: 15px 0;
|
||||
margin-left: 55px;
|
||||
margin-right: 20px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: stretch;
|
||||
}
|
||||
|
||||
#pages-container-wrapper {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
padding: 0.75rem;
|
||||
border-radius: 25px;
|
||||
min-height: 275px;
|
||||
margin: 0 0 20px 0;
|
||||
}
|
||||
|
||||
#pages-container {
|
||||
display: inline-flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 20px;
|
||||
justify-content: flex-start;
|
||||
width: fit-content;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
/* Scrollbar Styles */
|
||||
#pages-container-wrapper::-webkit-scrollbar {
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
}
|
||||
|
||||
#pages-container-wrapper::-webkit-scrollbar-track {
|
||||
background: var(--scroll-bar-color);
|
||||
}
|
||||
|
||||
#pages-container-wrapper::-webkit-scrollbar-thumb {
|
||||
border-radius: 10px;
|
||||
background: var(--scroll-bar-thumb);
|
||||
}
|
||||
|
||||
#pages-container-wrapper::-webkit-scrollbar-thumb:hover {
|
||||
background: var(--scroll-bar-thumb-hover);
|
||||
}
|
||||
|
||||
/* Page Container Base Styles */
|
||||
.page-container {
|
||||
display: inline-block;
|
||||
list-style-type: none;
|
||||
width: 260px;
|
||||
height: 260px;
|
||||
line-height: 50px;
|
||||
margin-top: 15px;
|
||||
box-sizing: border-box;
|
||||
text-align: center;
|
||||
aspect-ratio: 1;
|
||||
position: relative;
|
||||
user-select: none;
|
||||
transition: width 0.3s ease-in-out;
|
||||
}
|
||||
|
||||
/* Responsive Page Container Sizes */
|
||||
@media only screen and (max-width: 480px) {
|
||||
.page-container {
|
||||
width: calc(100vw - 90px);
|
||||
height: calc(100vw - 90px);
|
||||
max-width: 300px;
|
||||
max-height: 300px;
|
||||
margin: 5px auto;
|
||||
}
|
||||
#pages-container { gap: 10px; }
|
||||
}
|
||||
|
||||
@media only screen and (min-width: 481px) and (max-width: 768px) {
|
||||
.page-container {
|
||||
width: calc((100vw - 120px - 12px) / 2);
|
||||
height: calc((100vw - 120px - 12px) / 2);
|
||||
max-width: 250px;
|
||||
max-height: 250px;
|
||||
margin: 6px;
|
||||
}
|
||||
#pages-container { gap: 12px; }
|
||||
}
|
||||
|
||||
@media only screen and (min-width: 769px) and (max-width: 1199px) {
|
||||
.page-container {
|
||||
width: calc((100vw - 140px - 45px) / 3);
|
||||
height: calc((100vw - 140px - 45px) / 3);
|
||||
max-width: 220px;
|
||||
max-height: 220px;
|
||||
margin: 7px;
|
||||
}
|
||||
#pages-container { gap: 15px; }
|
||||
}
|
||||
|
||||
@media only screen and (min-width: 1200px) and (max-width: 1280px) {
|
||||
.page-container {
|
||||
width: calc((100vw - 160px - 60px) / 4);
|
||||
height: calc((100vw - 160px - 60px) / 4);
|
||||
max-width: 200px;
|
||||
max-height: 200px;
|
||||
margin: 8px;
|
||||
}
|
||||
#pages-container { gap: 17px; }
|
||||
}
|
||||
|
||||
@media only screen and (min-width: 1281px) {
|
||||
.page-container {
|
||||
width: calc((100vw - 180px - 80px) / 5);
|
||||
height: calc((100vw - 180px - 80px) / 5);
|
||||
max-width: 190px;
|
||||
max-height: 190px;
|
||||
margin: 10px;
|
||||
}
|
||||
#pages-container { gap: 20px; }
|
||||
}
|
||||
|
||||
/* Split Page Styles */
|
||||
.page-container.split-before {
|
||||
border-left: 1px dashed var(--md-sys-color-on-surface);
|
||||
padding-left: -1px;
|
||||
}
|
||||
|
||||
.page-container.split-before:first-child {
|
||||
border-left: none;
|
||||
}
|
||||
|
||||
.page-container:first-child .pdf-actions_split-file-button {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* RTL Language Support */
|
||||
.page-container:last-child:lang(ar),
|
||||
.page-container:last-child:lang(he),
|
||||
.page-container:last-child:lang(fa),
|
||||
.page-container:last-child:lang(ur),
|
||||
.page-container:last-child:lang(ckb),
|
||||
.page-container:last-child:lang(ks),
|
||||
.page-container:last-child:lang(kk),
|
||||
.page-container:last-child:lang(uz),
|
||||
.page-container:last-child:lang(ky),
|
||||
.page-container:last-child:lang(bal),
|
||||
.page-container:last-child:lang(dv),
|
||||
.page-container:last-child:lang(ps),
|
||||
.page-container:last-child:lang(sdg),
|
||||
.page-container:last-child:lang(syr),
|
||||
.page-container:last-child:lang(mzn),
|
||||
.page-container:last-child:lang(tgl),
|
||||
.page-container:last-child:lang(pnb),
|
||||
.page-container:last-child:lang(ug),
|
||||
.page-container:last-child:lang(nqo),
|
||||
.page-container:last-child:lang(bqi) {
|
||||
margin-left: auto !important;
|
||||
margin-right: 0 !important;
|
||||
}
|
||||
|
||||
/* Page Image Styles */
|
||||
.page-container img {
|
||||
max-width: calc(100% - 8px);
|
||||
max-height: calc(100% - 8px);
|
||||
display: block;
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
translate: -50% -50%;
|
||||
box-shadow: 0px 0px 8px rgba(0, 0, 0, 0.384);
|
||||
border-radius: 4px;
|
||||
transition: rotate 0.3s;
|
||||
}
|
||||
|
||||
/* Page Number Styles */
|
||||
.page-number {
|
||||
position: absolute;
|
||||
top: 5px;
|
||||
left: 5px;
|
||||
line-height: normal;
|
||||
color: var(--md-sys-color-on-secondary);
|
||||
background-color: rgba(162, 201, 255, 0.8);
|
||||
padding: 6px 8px;
|
||||
border-radius: 8px;
|
||||
font-size: 16px;
|
||||
z-index: 2;
|
||||
font-weight: 450;
|
||||
}
|
||||
|
||||
/* Tool Header and Button Styles */
|
||||
.tool-header {
|
||||
margin: 0.5rem 1rem 1rem;
|
||||
}
|
||||
|
||||
#select-pages-button {
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
#add-pdf-button {
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
/* Selected Pages Container Styles */
|
||||
.selected-pages-container {
|
||||
background-color: var(--md-sys-color-surface);
|
||||
border-radius: 16px;
|
||||
padding: 15px;
|
||||
width: 100%;
|
||||
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
|
||||
font-family: Arial, sans-serif;
|
||||
}
|
||||
|
||||
.selected-pages-container h3 {
|
||||
color: var(--md-sys-color-on-surface);
|
||||
font-size: 1.2em;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.selected-pages-header {
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
.selected-pages-header h5 {
|
||||
margin: 0 0 8px 0 !important;
|
||||
font-size: 1.1rem;
|
||||
font-weight: 600;
|
||||
color: var(--md-sys-color-on-surface);
|
||||
}
|
||||
|
||||
.selected-pages-header #csv-input {
|
||||
width: 100%;
|
||||
height: 2.5rem;
|
||||
border-radius: 8px;
|
||||
border: 1px solid var(--md-sys-color-outline);
|
||||
background-color: var(--md-sys-color-surface);
|
||||
color: var(--md-sys-color-on-surface);
|
||||
padding: 0 12px;
|
||||
font-size: 0.95rem;
|
||||
}
|
||||
|
||||
.selected-pages-header #csv-input:focus {
|
||||
outline: none;
|
||||
border-color: var(--md-sys-color-primary);
|
||||
box-shadow: 0 0 0 2px rgba(var(--md-sys-color-primary-rgb), 0.2);
|
||||
}
|
||||
|
||||
/* Pages List Styles */
|
||||
.pages-list {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 10px;
|
||||
padding: 0;
|
||||
list-style: none;
|
||||
min-height: 0;
|
||||
max-height: 10rem;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.page-item {
|
||||
background-color: var(--md-sys-color-surface-container-low);
|
||||
border-radius: 8px;
|
||||
padding: 8px 12px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
font-weight: bold;
|
||||
color: var(--md-sys-color-on-surface);
|
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
||||
width: 7rem;
|
||||
height: 2.5rem;
|
||||
}
|
||||
|
||||
.selected-page-number {
|
||||
width: 4rem;
|
||||
font-size: small;
|
||||
}
|
||||
|
||||
.remove-btn {
|
||||
cursor: pointer;
|
||||
color: var(--md-sys-color-on-surface);
|
||||
font-size: 1.2em;
|
||||
}
|
||||
|
||||
.checkbox-container {
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.checkbox-label {
|
||||
font-size: medium;
|
||||
}
|
||||
|
||||
/* Zoom Level Responsive Styles */
|
||||
@media only screen and (min-width: 2000px) {
|
||||
.mt-action-btn {
|
||||
gap: 12px;
|
||||
padding: 12px 24px;
|
||||
border-radius: 2.5rem;
|
||||
}
|
||||
.mt-action-btn .btn {
|
||||
width: 4rem;
|
||||
height: 4rem;
|
||||
border-radius: 22px;
|
||||
}
|
||||
.mt-action-btn .btn .material-symbols-rounded {
|
||||
font-size: 1.7rem;
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (min-width: 2560px) {
|
||||
.mt-action-btn {
|
||||
gap: 15px;
|
||||
padding: 15px 30px;
|
||||
border-radius: 3rem;
|
||||
}
|
||||
.mt-action-btn .btn {
|
||||
width: 5rem;
|
||||
height: 5rem;
|
||||
border-radius: 28px;
|
||||
}
|
||||
.mt-action-btn .btn .material-symbols-rounded {
|
||||
font-size: 2.1rem;
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (min-width: 3840px) {
|
||||
.mt-action-btn {
|
||||
gap: 20px;
|
||||
padding: 20px 40px;
|
||||
border-radius: 4rem;
|
||||
}
|
||||
.mt-action-btn .btn {
|
||||
width: 7rem;
|
||||
height: 7rem;
|
||||
border-radius: 40px;
|
||||
}
|
||||
.mt-action-btn .btn .material-symbols-rounded {
|
||||
font-size: 3rem;
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (min-width: 7680px) {
|
||||
.mt-action-btn {
|
||||
gap: 40px;
|
||||
padding: 40px 80px;
|
||||
border-radius: 8rem;
|
||||
}
|
||||
.mt-action-btn .btn {
|
||||
width: 14rem;
|
||||
height: 14rem;
|
||||
border-radius: 80px;
|
||||
}
|
||||
.mt-action-btn .btn .material-symbols-rounded {
|
||||
font-size: 6rem;
|
||||
}
|
||||
}
|
||||
|
||||
/* Zoom-responsive Sidebar Styles */
|
||||
@media only screen and (max-width: 1280px) {
|
||||
.container {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.mt-action-btn {
|
||||
position: fixed !important;
|
||||
left: 10px !important;
|
||||
top: 80px !important;
|
||||
bottom: 20px !important;
|
||||
margin: 0 !important;
|
||||
transform: none !important;
|
||||
border-radius: 16px !important;
|
||||
background-color: var(--md-sys-color-surface-container-low);
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
|
||||
backdrop-filter: blur(8px);
|
||||
display: flex !important;
|
||||
flex-direction: column !important;
|
||||
align-items: center !important;
|
||||
justify-content: center !important;
|
||||
height: calc(100vh - 100px) !important;
|
||||
overflow-y: auto !important;
|
||||
scrollbar-width: none !important;
|
||||
-ms-overflow-style: none !important;
|
||||
z-index: 12;
|
||||
width: 70px !important;
|
||||
gap: 8px !important;
|
||||
padding: 12px 8px !important;
|
||||
box-sizing: border-box !important;
|
||||
}
|
||||
|
||||
.mt-action-btn:has(.btn:nth-last-child(n+7)) {
|
||||
justify-content: flex-start !important;
|
||||
}
|
||||
|
||||
.mt-action-btn::-webkit-scrollbar {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.mt-action-btn .btn {
|
||||
width: 48px !important;
|
||||
height: 48px !important;
|
||||
border-radius: 12px !important;
|
||||
padding: 0 !important;
|
||||
margin: 0 !important;
|
||||
flex-shrink: 0;
|
||||
font-size: 16px !important;
|
||||
box-sizing: border-box !important;
|
||||
}
|
||||
|
||||
.mt-action-btn .btn .material-symbols-rounded {
|
||||
font-size: 20px !important;
|
||||
line-height: 1 !important;
|
||||
display: flex !important;
|
||||
align-items: center !important;
|
||||
justify-content: center !important;
|
||||
width: 100% !important;
|
||||
height: 100% !important;
|
||||
font-variation-settings: 'FILL' 0, 'wght' 400, 'GRAD' 0, 'opsz' 24 !important;
|
||||
}
|
||||
|
||||
.multi-tool-container {
|
||||
margin-left: 0 !important;
|
||||
max-width: 100% !important;
|
||||
}
|
||||
|
||||
.mt-action-bar {
|
||||
margin-left: 25px !important;
|
||||
margin-right: 25px !important;
|
||||
}
|
||||
|
||||
.mt-action-btn:not(:has(*:nth-child(6))) {
|
||||
justify-content: center !important;
|
||||
}
|
||||
}
|
||||
|
||||
/* Mobile and High Zoom Responsive Styles */
|
||||
@media only screen and (max-width: 960px) {
|
||||
.mt-action-btn {
|
||||
left: 8px !important;
|
||||
top: 75px !important;
|
||||
bottom: 15px !important;
|
||||
height: calc(100vh - 90px) !important;
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 768px) {
|
||||
.mt-action-btn {
|
||||
left: 5px !important;
|
||||
width: 60px !important;
|
||||
top: calc(var(--navbar-height, 60px) + 10px) !important;
|
||||
bottom: 10px !important;
|
||||
height: calc(100vh - var(--navbar-height, 60px) - 20px) !important;
|
||||
}
|
||||
|
||||
.mt-action-btn .btn {
|
||||
width: 40px !important;
|
||||
height: 40px !important;
|
||||
box-sizing: border-box !important;
|
||||
}
|
||||
|
||||
.mt-action-btn .btn .material-symbols-rounded {
|
||||
font-size: 16px !important;
|
||||
}
|
||||
|
||||
#pages-container {
|
||||
margin: 0 auto !important;
|
||||
display: flex !important;
|
||||
flex-wrap: wrap !important;
|
||||
justify-content: center !important;
|
||||
width: 100% !important;
|
||||
}
|
||||
|
||||
.page-container {
|
||||
width: calc(100vw - 55px) !important;
|
||||
height: calc(100vw - 60px) !important;
|
||||
max-width: 350px !important;
|
||||
max-height: 350px !important;
|
||||
margin: 5px auto !important;
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 480px) {
|
||||
.mt-action-btn {
|
||||
left: 2px !important;
|
||||
top: calc(var(--navbar-height, 60px) + 5px) !important;
|
||||
bottom: 5px !important;
|
||||
height: calc(100vh - var(--navbar-height, 60px) - 10px) !important;
|
||||
width: 50px !important;
|
||||
gap: 6px !important;
|
||||
padding: 10px 6px !important;
|
||||
}
|
||||
|
||||
.mt-action-btn .btn {
|
||||
width: 32px !important;
|
||||
height: 32px !important;
|
||||
border-radius: 10px !important;
|
||||
box-sizing: border-box !important;
|
||||
}
|
||||
|
||||
.mt-action-btn .btn .material-symbols-rounded {
|
||||
font-size: 14px !important;
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 384px) {
|
||||
.mt-action-btn {
|
||||
left: 2px !important;
|
||||
top: calc(var(--navbar-height, 60px) + 5px) !important;
|
||||
bottom: 5px !important;
|
||||
height: calc(100vh - var(--navbar-height, 60px) - 10px) !important;
|
||||
width: 40px !important;
|
||||
gap: 4px !important;
|
||||
padding: 8px 4px !important;
|
||||
}
|
||||
|
||||
.mt-action-btn .btn {
|
||||
width: 28px !important;
|
||||
height: 28px !important;
|
||||
border-radius: 8px !important;
|
||||
box-sizing: border-box !important;
|
||||
}
|
||||
|
||||
.mt-action-btn .btn .material-symbols-rounded {
|
||||
font-size: 12px !important;
|
||||
}
|
||||
|
||||
.page-container {
|
||||
width: calc(100vw - 55px) !important;
|
||||
height: calc(100vw - 60px) !important;
|
||||
max-width: 280px !important;
|
||||
max-height: 280px !important;
|
||||
margin: 3px auto !important;
|
||||
}
|
||||
|
||||
.page-container img {
|
||||
max-width: calc(100% - 4px) !important;
|
||||
max-height: calc(100% - 4px) !important;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,799 +0,0 @@
|
||||
#navbarSearch {
|
||||
top: 100%;
|
||||
right: 0;
|
||||
transition: all 0.3s;
|
||||
max-height: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
#navbarSearch.show {
|
||||
height: auto;
|
||||
/*dynamically changes height*/
|
||||
}
|
||||
|
||||
#searchResults .dropdown-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
white-space: nowrap;
|
||||
height: 50px;
|
||||
/* Fixed height */
|
||||
overflow: hidden;
|
||||
/* Hide overflow */
|
||||
}
|
||||
|
||||
#searchResults .icon {
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
#searchResults .icon-text {
|
||||
display: inline;
|
||||
overflow: hidden;
|
||||
/* Hide overflow */
|
||||
text-overflow: ellipsis;
|
||||
/* Add ellipsis for long text */
|
||||
}
|
||||
|
||||
#search-icon i {
|
||||
font-size: 24px;
|
||||
/* Adjust this to your desired size */
|
||||
transition: color 0.3s;
|
||||
}
|
||||
|
||||
#search-icon:hover i {
|
||||
color: #666;
|
||||
/* Adjust this to your hover color */
|
||||
}
|
||||
|
||||
.search-input {
|
||||
transition: border 0.3s, box-shadow 0.3s;
|
||||
}
|
||||
|
||||
.search-input:focus {
|
||||
border-color: #666;
|
||||
/* Adjust this to your focus color */
|
||||
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
|
||||
/* Adjust this to your desired shadow */
|
||||
}
|
||||
|
||||
|
||||
.main-icon {
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
vertical-align: middle;
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
|
||||
/* Responsive navbar brand - prevent hamburger from wrapping */
|
||||
.navbar-brand {
|
||||
display: flex !important;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
min-width: 0; /* Allow shrinking */
|
||||
}
|
||||
|
||||
.navbar-brand .icon-text {
|
||||
font-size: 1.5rem;
|
||||
font-weight: bold;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
/* Progressive text shrinking to prevent hamburger wrap */
|
||||
@media only screen and (max-width: 480px) {
|
||||
.navbar-brand .icon-text {
|
||||
font-size: 1.3rem;
|
||||
}
|
||||
|
||||
.main-icon {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 420px) {
|
||||
.navbar-brand .icon-text {
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
|
||||
.main-icon {
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 380px) {
|
||||
.navbar-brand .icon-text {
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
.main-icon {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 340px) {
|
||||
.navbar-brand .icon-text {
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
.main-icon {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
/* Ultra-small screens - hide text, keep icon */
|
||||
@media only screen and (max-width: 320px) {
|
||||
.navbar-brand .icon-text {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.main-icon {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
}
|
||||
}
|
||||
|
||||
.nav-icon {
|
||||
vertical-align: middle;
|
||||
font-size: 2rem !important;
|
||||
padding: 0.25rem;
|
||||
border-radius: 1rem;
|
||||
}
|
||||
|
||||
.icon+.icon {
|
||||
margin-left: -4px;
|
||||
}
|
||||
|
||||
.icon-text {
|
||||
margin-left: 8px;
|
||||
margin-right: 4px;
|
||||
display: inline-flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
|
||||
.scalable-languages-container {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(1, 1fr);
|
||||
}
|
||||
|
||||
@media (min-width: 400px) {
|
||||
#languageSelection.scalable-languages-container {
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
}
|
||||
}
|
||||
@media (min-width: 600px) {
|
||||
#languageSelection.scalable-languages-container {
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
}
|
||||
}
|
||||
@media (min-width: 900px) {
|
||||
#languageSelection.scalable-languages-container {
|
||||
grid-template-columns: repeat(4, 1fr) !important;
|
||||
}
|
||||
}
|
||||
|
||||
.scalable-languages-container:not(:has(> :nth-child(4))) .lang-dropdown-item-wrapper:last-child {
|
||||
border: 0px !important
|
||||
}
|
||||
|
||||
html[dir="ltr"] #languageSelection .lang-dropdown-item-wrapper:last-child {
|
||||
border-right: none !important;
|
||||
}
|
||||
|
||||
#languageSelection .lang-dropdown-item-wrapper:last-child {
|
||||
border: 0px !important;
|
||||
}
|
||||
@media (max-width: 600px) {
|
||||
.scalable-languages-container {
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
}
|
||||
|
||||
.scalable-languages-container:not(:has(> :nth-child(2))) {
|
||||
grid-template-columns: repeat(var(--count), 1fr) !important;
|
||||
}
|
||||
|
||||
.scalable-languages-container .lang-dropdown-item-wrapper:nth-child(2n) {
|
||||
border: 0px
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 601px) and (max-width: 900px) {
|
||||
.scalable-languages-container {
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
}
|
||||
|
||||
.scalable-languages-container:not(:has(> :nth-child(3))) {
|
||||
grid-template-columns: repeat(var(--count), 1fr) !important;
|
||||
}
|
||||
|
||||
.scalable-languages-container .lang-dropdown-item-wrapper:nth-child(3n) {
|
||||
border: 0px
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 901px) {
|
||||
.scalable-languages-container {
|
||||
grid-template-columns: repeat(4, 1fr);
|
||||
}
|
||||
|
||||
.scalable-languages-container:not(:has(> :nth-child(4))) {
|
||||
grid-template-columns: repeat(var(--count), 1fr) !important;
|
||||
}
|
||||
|
||||
.scalable-languages-container .lang-dropdown-item-wrapper:nth-child(4n) {
|
||||
border: 0px
|
||||
}
|
||||
}
|
||||
|
||||
.scalable-languages-container:has(> *:nth-child(1)) {
|
||||
--count: 1;
|
||||
}
|
||||
|
||||
.scalable-languages-container:has(> *:nth-child(2)) {
|
||||
--count: 2;
|
||||
}
|
||||
|
||||
.scalable-languages-container:has(> *:nth-child(3)) {
|
||||
--count: 3;
|
||||
}
|
||||
|
||||
html[dir="ltr"] .lang-dropdown-item-wrapper {
|
||||
border-right: 2px solid var(--md-nav-color-on-separator);
|
||||
}
|
||||
|
||||
html[dir="rtl"] .lang-dropdown-item-wrapper {
|
||||
border-left: 2px solid var(--md-nav-color-on-separator);
|
||||
}
|
||||
|
||||
.scroll-lock-y {
|
||||
overflow-y: auto;
|
||||
max-height: 30vh;
|
||||
overscroll-behavior-y: contain;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
}
|
||||
|
||||
/* Responsive adjustments */
|
||||
@media (min-width: 1200px) {
|
||||
.lang-dropdown-item-wrapper .dropdown-item {
|
||||
min-width: 200px
|
||||
}
|
||||
|
||||
.scroll-lock-y {
|
||||
max-height: 80vh;
|
||||
}
|
||||
}
|
||||
|
||||
.dropdown-item .icon-text {
|
||||
text-wrap: wrap;
|
||||
word-break: break-word;
|
||||
width: 80%;
|
||||
font-size: large;
|
||||
}
|
||||
|
||||
.close-icon {
|
||||
color: var(--md-sys-color-secondary);
|
||||
}
|
||||
|
||||
.close-icon:hover {
|
||||
transform: scale(1.15);
|
||||
}
|
||||
|
||||
span.icon-text::after {
|
||||
content: attr(data-text);
|
||||
content: attr(data-text) / "";
|
||||
font-weight: 600;
|
||||
height: 0;
|
||||
visibility: hidden;
|
||||
overflow: hidden;
|
||||
user-select: none;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.nav-item-separator {
|
||||
position: relative;
|
||||
margin: 0 4px;
|
||||
/* Adjust the margin as needed */
|
||||
}
|
||||
|
||||
.nav-item-separator::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 10%;
|
||||
/* Adjust the top and bottom margins as needed */
|
||||
bottom: 10%;
|
||||
width: 1px;
|
||||
background-color: #ccc;
|
||||
/* Adjust the color as needed */
|
||||
}
|
||||
|
||||
.navbar-icon {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
|
||||
.navbar-toggler {
|
||||
color: var(--md-sys-color-on-surface-variant);
|
||||
}
|
||||
|
||||
.nav-link {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
max-width: 98vw;
|
||||
}
|
||||
|
||||
.chevron-icon {
|
||||
margin-left: auto;
|
||||
transition: transform 0.3s ease;
|
||||
}
|
||||
|
||||
[aria-expanded="true"] > .chevron-icon {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
|
||||
.nav-item {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
/* .tooltip-text {
|
||||
visibility: hidden;
|
||||
background-color: rgb(71 67 67 / 80%);
|
||||
color: #fff;
|
||||
text-align: center;
|
||||
border-radius: 4px;
|
||||
padding: 5px;
|
||||
position: absolute;
|
||||
z-index: 1;
|
||||
top: 100%;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
opacity: 0;
|
||||
transition: opacity 0.3s;
|
||||
font-size: 12px;
|
||||
white-space: nowrap;
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
.nav-item:hover .tooltip-text {
|
||||
visibility: visible;
|
||||
opacity: 1;
|
||||
} */
|
||||
|
||||
.dropdown-menu.scrollable-y {
|
||||
overflow-y: scroll;
|
||||
max-height: 360px;
|
||||
}
|
||||
|
||||
/* Dropdown Scrollbar*/
|
||||
.scrollable-y {
|
||||
overflow-y: scroll;
|
||||
max-height: 190px;
|
||||
overscroll-behavior: contain;
|
||||
}
|
||||
|
||||
.scrollable-y::-webkit-scrollbar {
|
||||
background: transparent;
|
||||
width: 0.7rem;
|
||||
}
|
||||
|
||||
.scrollable-y::-webkit-scrollbar-track {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.scrollable-y::-webkit-scrollbar-thumb {
|
||||
border-radius: 2rem;
|
||||
background-color: var(--md-sys-color-surface-5);
|
||||
border: 3px solid var(--md-sys-color-surface-5);
|
||||
}
|
||||
|
||||
/* Mega Menu */
|
||||
.dropdown-mega .dropdown-menu {
|
||||
width: 100%;
|
||||
left: 0 !important;
|
||||
right: auto !important;
|
||||
}
|
||||
|
||||
.dropdown-mega .title {
|
||||
padding-bottom: 1rem;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.dropdown-menu .list-group {
|
||||
padding: 1rem;
|
||||
}
|
||||
|
||||
.mega-content .dropdown-item:focus .nav-icon,
|
||||
.mega-content .dropdown-item:hover .nav-icon,
|
||||
.mega-content .dropdown-item.active .nav-icon {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.dropdown-item:focus.sign,
|
||||
.dropdown-item:hover.sign,
|
||||
.dropdown-item.active.sign {
|
||||
color: var(--md-nav-on-section-color-sign);
|
||||
background-color: var(--md-nav-section-color-sign);
|
||||
}
|
||||
|
||||
.dropdown-item:focus.organize,
|
||||
.dropdown-item:hover.organize,
|
||||
.dropdown-item.active.organize {
|
||||
color: var(--md-nav-on-section-color-organize);
|
||||
background-color: var(--md-nav-section-color-organize);
|
||||
}
|
||||
|
||||
.dropdown-item:focus.convert,
|
||||
.dropdown-item:hover.convert,
|
||||
.dropdown-item.active.convert {
|
||||
color: var(--md-nav-on-section-color-convert);
|
||||
background-color: var(--md-nav-section-color-convert);
|
||||
}
|
||||
|
||||
.dropdown-item:focus.convertto,
|
||||
.dropdown-item:hover.convertto,
|
||||
.dropdown-item.active.convertto {
|
||||
color: var(--md-nav-on-section-color-convertto);
|
||||
background-color: var(--md-nav-section-color-convertto);
|
||||
}
|
||||
|
||||
.dropdown-item:focus.image,
|
||||
.dropdown-item:hover.image,
|
||||
.dropdown-item.active.image {
|
||||
color: var(--md-nav-on-section-color-image);
|
||||
background-color: var(--md-nav-section-color-image);
|
||||
}
|
||||
|
||||
.dropdown-item:focus.word,
|
||||
.dropdown-item:hover.word,
|
||||
.dropdown-item.active.word {
|
||||
color: var(--md-nav-on-section-color-word);
|
||||
background-color: var(--md-nav-section-color-word);
|
||||
}
|
||||
|
||||
.dropdown-item:focus.ppt,
|
||||
.dropdown-item:hover.ppt,
|
||||
.dropdown-item.active.ppt {
|
||||
color: var(--md-nav-on-section-color-ppt);
|
||||
background-color: var(--md-nav-section-color-ppt);
|
||||
}
|
||||
|
||||
.dropdown-item:focus.security,
|
||||
.dropdown-item:hover.security,
|
||||
.dropdown-item.active.security {
|
||||
color: var(--md-nav-on-section-color-security);
|
||||
background-color: var(--md-nav-section-color-security);
|
||||
}
|
||||
|
||||
.dropdown-item:focus.other,
|
||||
.dropdown-item:hover.other,
|
||||
.dropdown-item.active.other {
|
||||
color: var(--md-nav-on-section-color-other);
|
||||
background-color: var(--md-nav-section-color-other);
|
||||
}
|
||||
|
||||
.dropdown-item:focus.advance,
|
||||
.dropdown-item:hover.advance,
|
||||
.dropdown-item.active.advance {
|
||||
color: var(--md-nav-on-section-color-advance);
|
||||
background-color: var(--md-nav-section-color-advance);
|
||||
}
|
||||
|
||||
/* Dropdown min-width */
|
||||
.dropdown-mw-28 {
|
||||
min-width: 280px;
|
||||
min-height: 50px;
|
||||
}
|
||||
|
||||
.dropdown-mw-20 {
|
||||
min-width: 200px;
|
||||
}
|
||||
|
||||
/* Dropdown open on hover */
|
||||
html[dir="ltr"] .dropdown-menu {
|
||||
padding-top: 0.5rem;
|
||||
top: auto;
|
||||
left: auto;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
html[dir="rtl"] .dropdown-menu {
|
||||
padding-top: 0.5rem;
|
||||
top: auto;
|
||||
left: 0;
|
||||
right: auto;
|
||||
}
|
||||
|
||||
/* Bootstrap Popper positioning overrides removed - dropdowns now position naturally relative to their buttons */
|
||||
|
||||
.dropdown-menu-wrapper {
|
||||
padding: 1.5rem 0;
|
||||
border-radius: 1rem;
|
||||
color: var(--md-sys-color-on-surface);
|
||||
background-color: var(--md-sys-color-surface);
|
||||
border: 1px solid var(--md-sys-color-surface-5);
|
||||
box-shadow: var(--md-sys-elevation-2);
|
||||
}
|
||||
|
||||
|
||||
.dropdown-menu-tp {
|
||||
color: transparent;
|
||||
background-color: transparent;
|
||||
border: none;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.icon-hide {
|
||||
display: inline-flex;
|
||||
}
|
||||
|
||||
@media (max-width:1199.98px) {
|
||||
.navbar-collapse .dropdown-menu {
|
||||
width: 100%;
|
||||
}
|
||||
.navbar-collapse .dropdown-menu-wrapper {
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.navbar-collapse .dropdown-mw-28 {
|
||||
min-width: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width:1200px) {
|
||||
/* This CSS-based hover is disabled because it conflicts with Bootstrap's JavaScript.
|
||||
Hover functionality is now handled in navbar.js and search.js */
|
||||
/*
|
||||
.dropdown:hover .dropdown-menu {
|
||||
display: block;
|
||||
margin-top: 0;
|
||||
}
|
||||
*/
|
||||
|
||||
.icon-hide {
|
||||
display: none;
|
||||
}
|
||||
.chevron-icon {
|
||||
display: none !important;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 1199.98px) {
|
||||
.navbar-collapse .dropdown-menu {
|
||||
width: 100vw !important;
|
||||
max-width: 100vw !important;
|
||||
left: 0 !important;
|
||||
right: 0 !important;
|
||||
transform: none !important;
|
||||
transform-origin: none !important;
|
||||
}
|
||||
|
||||
.navbar .navbar-expand-xl .dropdown-menu,
|
||||
.navbar-expand .dropdown-menu {
|
||||
transform: none !important;
|
||||
transform-origin: none !important;
|
||||
left: 0 !important;
|
||||
right: 0 !important;
|
||||
}
|
||||
|
||||
.navbar-collapse .dropdown-mega .dropdown-menu {
|
||||
max-height: 60vh;
|
||||
overflow-y: auto;
|
||||
}
|
||||
.navbar-collapse .dropdown-mega .dropdown-menu-wrapper {
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
#favoritesDropdown,
|
||||
#languageDropdown + .dropdown-menu .dropdown-menu-wrapper,
|
||||
#searchDropdown + .dropdown-menu .dropdown-menu-wrapper {
|
||||
padding: 1.5rem 1rem;
|
||||
}
|
||||
|
||||
#favoritesDropdown, #languageSelection, #searchResults {
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.navbar-collapse .dropdown-menu-wrapper {
|
||||
width: 95vw;
|
||||
box-sizing: border-box;
|
||||
margin-left: 0 !important;
|
||||
padding: 0 !important;
|
||||
}
|
||||
.navbar-collapse .dropdown-mw-28 {
|
||||
min-width: 0;
|
||||
}
|
||||
.icon-hide {
|
||||
display: inline-flex;
|
||||
}
|
||||
|
||||
.navbar-collapse .dropdown-item {
|
||||
margin-left: 0 !important;
|
||||
}
|
||||
|
||||
.container {
|
||||
margin-left: auto !important;
|
||||
margin-right: auto !important;
|
||||
padding-left: 4px !important;
|
||||
}
|
||||
|
||||
#mainNavbarDropdownMenu {
|
||||
transform: none !important;
|
||||
transform-origin: none !important;
|
||||
left: 0 !important;
|
||||
right: 0 !important;
|
||||
width: 100vw !important;
|
||||
margin-bottom: 0 !important;
|
||||
}
|
||||
|
||||
.dropdown-menu,
|
||||
.dropdown-menu-tp,
|
||||
.dropdown-menu-tp.show {
|
||||
transform: none !important;
|
||||
transform-origin: none !important;
|
||||
max-width: 95vw !important;
|
||||
width: 100vw !important;
|
||||
left: 0 !important;
|
||||
right: 0 !important;
|
||||
margin-bottom: 0 !important;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
.go-pro-link {
|
||||
position: relative;
|
||||
padding: 0.5rem 1rem;
|
||||
transition: all 0.3s ease;
|
||||
z-index: 1;
|
||||
display: inline-block;
|
||||
width: auto;
|
||||
}
|
||||
|
||||
.go-pro-badge {
|
||||
display: inline-block;
|
||||
padding: 0.25rem 0.5rem;
|
||||
font-size: 0.75rem;
|
||||
font-weight: bold;
|
||||
color: #ffffff;
|
||||
background-color: #007bff;
|
||||
border-radius: 0.25rem;
|
||||
text-transform: uppercase;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.go-pro-link:hover .go-pro-badge {
|
||||
background-color: #0056b3;
|
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
|
||||
#stacked {
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
#stacked>.navbar-item {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.features-container {
|
||||
display: flex;
|
||||
gap: 30px;
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.feature-group {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-width: 14rem;
|
||||
max-width: 18rem;
|
||||
flex: 1 1 min(14rem, 100%);
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.feature-group {
|
||||
min-width: 10rem;
|
||||
}
|
||||
}
|
||||
|
||||
.feature-rows {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: flex-start;
|
||||
gap: 1rem;
|
||||
padding: 0 1rem;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.feature-rows.single-column {
|
||||
justify-content: center;
|
||||
/* Center-align a single column */
|
||||
}
|
||||
|
||||
.feature-group-header {
|
||||
display: flex;
|
||||
justify-content: flex-start;
|
||||
color: var(--md-sys-color-on-surface);
|
||||
margin-top: 15px;
|
||||
user-select: none;
|
||||
cursor: pointer;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.nav-group-container {
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
|
||||
|
||||
.card-title.text-primary {
|
||||
color: #000;
|
||||
}
|
||||
|
||||
.home-card-icon {
|
||||
width: 3rem;
|
||||
height: 3rem;
|
||||
transform: translateY(-5px);
|
||||
}
|
||||
|
||||
.favorite-icon {
|
||||
display: none;
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
right: 10px;
|
||||
color: var(--md-sys-color-secondary);
|
||||
}
|
||||
|
||||
.favorite-icon img {
|
||||
filter: brightness(0) invert(var(--md-theme-filter-color));
|
||||
}
|
||||
|
||||
.favorite-icon:hover .material-symbols-rounded {
|
||||
transform: scale(1.2);
|
||||
}
|
||||
|
||||
.favorite-icon .material-symbols-rounded.fill {
|
||||
color: #f5c000;
|
||||
}
|
||||
|
||||
|
||||
@keyframes Pulse {
|
||||
from {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
50% {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
to {
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.update-notice {
|
||||
animation: scale 1s infinite alternate;
|
||||
}
|
||||
|
||||
@keyframes scale {
|
||||
0% {
|
||||
transform: scale(0.96);
|
||||
}
|
||||
|
||||
100% {
|
||||
transform: scale(1);
|
||||
}
|
||||
}
|
||||
|
||||
.hidden {
|
||||
visibility: hidden;
|
||||
}
|
||||
@@ -1,117 +0,0 @@
|
||||
.pdf-actions_button-container {
|
||||
z-index: 4;
|
||||
opacity: 0;
|
||||
transition: opacity 0.1s linear;
|
||||
|
||||
position: absolute !important;
|
||||
bottom: 0px;
|
||||
left: 50%;
|
||||
transform: translate(-50%, 0%);
|
||||
}
|
||||
|
||||
.pdf-actions_container:hover .pdf-actions_button-container {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.pdf-actions_button-container>* {
|
||||
padding: 0.25rem 0.5rem;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.pdf-actions_button-container>*:focus {
|
||||
box-shadow: none !important;
|
||||
}
|
||||
|
||||
.pdf-actions_button-container .btn {
|
||||
border-radius: 12px;
|
||||
}
|
||||
|
||||
.pdf-actions_button-container> :first-child,
|
||||
.pdf-actions_container:first-child>.pdf-actions_button-container> :first-child+* {
|
||||
border-radius: 12px 0px 0px 12px;
|
||||
}
|
||||
|
||||
.pdf-actions_container svg {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
}
|
||||
|
||||
.pdf-actions_container:nth-child(1) .pdf-actions_move-left-button {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.pdf-actions_container:last-child .pdf-actions_move-right-button {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* "insert pdf" buttons that appear on the right when hover */
|
||||
.pdf-actions_insert-file-button-container {
|
||||
display:flex;
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
translate: 0 -50%;
|
||||
height: 100%;
|
||||
width: 100px;
|
||||
padding-left: 30px;
|
||||
padding-right:30px;
|
||||
justify-content: center;
|
||||
z-index: 3;
|
||||
opacity: 0;
|
||||
transition: opacity 0.4s;
|
||||
|
||||
}
|
||||
|
||||
.pdf-actions_insert-file-button-container.left {
|
||||
left: -50px;
|
||||
}
|
||||
|
||||
.pdf-actions_insert-file-button-container.right {
|
||||
right: -50px;
|
||||
}
|
||||
|
||||
html[dir="ltr"] .pdf-actions_insert-file-button-container.right {
|
||||
display: none;
|
||||
}
|
||||
|
||||
html[dir="rtl"] .pdf-actions_insert-file-button-container.left {
|
||||
display: none;
|
||||
}
|
||||
|
||||
html[dir="ltr"] .pdf-actions_container:last-child>.pdf-actions_insert-file-button-container.right {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
html[dir="rtl"] .pdf-actions_container:last-child>.pdf-actions_insert-file-button-container.left {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.pdf-actions_insert-file-button-container.left button,
|
||||
.pdf-actions_insert-file-button-container.right button {
|
||||
padding: 0.45rem;
|
||||
}
|
||||
|
||||
.pdf-actions_button-container button .material-symbols-rounded {
|
||||
font-size: 1.25rem;
|
||||
vertical-align: sub;
|
||||
}
|
||||
|
||||
.pdf-actions_insert-file-button-container:hover {
|
||||
opacity: 1;
|
||||
transition: opacity 0.05s;
|
||||
}
|
||||
|
||||
.pdf-actions_checkbox {
|
||||
position: absolute;
|
||||
top: 5px;
|
||||
right: 3px;
|
||||
color: var(--md-sys-color-on-surface);
|
||||
background-color: var(--md-sys-color-surface-5);
|
||||
padding: 6px 8px;
|
||||
border-radius: 8px;
|
||||
font-size: 16px;
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
.hidden {
|
||||
display: none;
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
.filename {
|
||||
flex-grow: 1;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.arrows {
|
||||
flex-shrink: 0;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
.arrows .btn {
|
||||
margin: 0 3px;
|
||||
}
|
||||
|
||||
.move-up span,
|
||||
.move-down span {
|
||||
font-weight: bold;
|
||||
font-size: 1.2em;
|
||||
}
|
||||
@@ -1,973 +0,0 @@
|
||||
/* Dark Mode Styles */
|
||||
body,
|
||||
select,
|
||||
textarea {
|
||||
background-color: var(--md-sys-color-surface);
|
||||
color: var(--md-sys-color-on-surface);
|
||||
}
|
||||
|
||||
.transition-theme {
|
||||
transition: background 0.5s ease, color 0.5s ease, border 0.5s ease;
|
||||
}
|
||||
|
||||
|
||||
/*.global-buttons-container input:disabled::-webkit-input-placeholder { !* WebKit browsers *!*/
|
||||
/* color: #98A0AB;*/
|
||||
/*}*/
|
||||
/*.global-buttons-container input:disabled:-moz-placeholder { !* Mozilla Firefox 4 to 18 *!*/
|
||||
/* color: #98A0AB;*/
|
||||
/*}*/
|
||||
/*.global-buttons-container input:disabled::-moz-placeholder { !* Mozilla Firefox 19+ *!*/
|
||||
/* color: #98A0AB;*/
|
||||
/*}*/
|
||||
/*.global-buttons-container input:disabled:-ms-input-placeholder { !* Internet Explorer 10+ *!*/
|
||||
/* color: #98A0AB;*/
|
||||
/*}*/
|
||||
/* Scrollbar */
|
||||
*::-webkit-scrollbar {
|
||||
background: var(--md-sys-color-surface);
|
||||
width: 1rem;
|
||||
}
|
||||
|
||||
*::-webkit-scrollbar-track {
|
||||
background: var(--md-sys-color-surface);
|
||||
}
|
||||
|
||||
*::-webkit-scrollbar-thumb {
|
||||
border-radius: 2rem;
|
||||
background-color: var(--md-sys-color-surface-5);
|
||||
border: 5px solid var(--md-sys-color-surface-5);
|
||||
}
|
||||
|
||||
*::-webkit-scrollbar-corner {
|
||||
background-color: var(--md-sys-color-surface);
|
||||
}
|
||||
|
||||
/* Alerts */
|
||||
.alert {
|
||||
border-radius: 3rem;
|
||||
}
|
||||
|
||||
/* Table */
|
||||
td {
|
||||
word-break: break-word;
|
||||
}
|
||||
|
||||
.input-group-append {
|
||||
margin: 0rem 0.5rem !important;
|
||||
}
|
||||
|
||||
.card-header {
|
||||
background-color: transparent;
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.bg-card {
|
||||
background-color: var(--md-sys-color-surface-5);
|
||||
border-radius: 3rem;
|
||||
padding: 2.5rem;
|
||||
|
||||
max-width: 95vw;
|
||||
margin-left: 2vw;
|
||||
}
|
||||
|
||||
.card {
|
||||
padding: 1.25rem;
|
||||
border-radius: 2rem;
|
||||
background-color: var(--md-sys-color-surface-5);
|
||||
border: none;
|
||||
}
|
||||
|
||||
/* Modal */
|
||||
.modal-content {
|
||||
background-color: var(--md-sys-color-surface);
|
||||
border-radius: 2rem;
|
||||
border: transparent;
|
||||
}
|
||||
|
||||
.modal-header,
|
||||
.modal-body,
|
||||
.modal-footer {
|
||||
background-color: var(--md-sys-color-surface-5);
|
||||
|
||||
border: none;
|
||||
}
|
||||
|
||||
.modal-header {
|
||||
border-radius: 2rem 2rem 0rem 0rem;
|
||||
padding: 1.5rem 2rem 0.5rem;
|
||||
}
|
||||
|
||||
.modal-body{
|
||||
padding: 0.5rem 2rem;
|
||||
}
|
||||
|
||||
.modal-footer {
|
||||
border-radius: 0rem 0rem 2rem 2rem;
|
||||
padding: 0.5rem 2rem 1.5rem;
|
||||
}
|
||||
|
||||
/* Icon fill */
|
||||
.material-symbols-rounded {
|
||||
vertical-align: text-top;
|
||||
}
|
||||
|
||||
/* Navbar Icon*/
|
||||
.nav-icon {
|
||||
color: var(--md-sys-color-surface);
|
||||
}
|
||||
|
||||
.sign .nav-icon,
|
||||
.sign.tool-header-icon {
|
||||
color: var(--md-nav-on-section-color-sign);
|
||||
background-color: var(--md-nav-section-color-sign);
|
||||
}
|
||||
|
||||
.organize .nav-icon,
|
||||
.organize.tool-header-icon {
|
||||
color: var(--md-nav-on-section-color-organize);
|
||||
background-color: var(--md-nav-section-color-organize);
|
||||
}
|
||||
|
||||
.convert .nav-icon,
|
||||
.convert.tool-header-icon {
|
||||
color: var(--md-nav-on-section-color-convert);
|
||||
background-color: var(--md-nav-section-color-convert);
|
||||
}
|
||||
|
||||
.convertto .nav-icon,
|
||||
.convertto.tool-header-icon {
|
||||
color: var(--md-nav-on-section-color-convertto);
|
||||
background-color: var(--md-nav-section-color-convertto);
|
||||
}
|
||||
|
||||
|
||||
.security .nav-icon,
|
||||
.security.tool-header-icon {
|
||||
color: var(--md-nav-on-section-color-security);
|
||||
background-color: var(--md-nav-section-color-security);
|
||||
}
|
||||
|
||||
.other .nav-icon,
|
||||
.other.tool-header-icon {
|
||||
color: var(--md-nav-on-section-color-other);
|
||||
background-color: var(--md-nav-section-color-other);
|
||||
}
|
||||
|
||||
.advance .nav-icon,
|
||||
.advance.tool-header-icon {
|
||||
color: var(--md-nav-on-section-color-advance);
|
||||
background-color: var(--md-nav-section-color-advance);
|
||||
}
|
||||
|
||||
.image .nav-icon,
|
||||
.image.tool-header-icon {
|
||||
color: var(--md-nav-on-section-color-image);
|
||||
background-color: var(--md-nav-section-color-image);
|
||||
}
|
||||
|
||||
.word .nav-icon,
|
||||
.word.tool-header-icon {
|
||||
color: var(--md-nav-on-section-color-word);
|
||||
background-color: var(--md-nav-section-color-word);
|
||||
}
|
||||
|
||||
.ppt .nav-icon,
|
||||
.ppt.tool-header-icon {
|
||||
color: var(--md-nav-on-section-color-ppt);
|
||||
background-color: var(--md-nav-section-color-ppt);
|
||||
}
|
||||
|
||||
/* Tool Page Header*/
|
||||
.tool-header {
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
|
||||
.tool-header .tool-header-icon {
|
||||
margin: 0px 1rem;
|
||||
height: 4rem;
|
||||
width: 4rem;
|
||||
border-radius: 25px;
|
||||
font-size: 3rem;
|
||||
padding: 0.5rem;
|
||||
vertical-align: middle;
|
||||
pointer-events: none;
|
||||
user-select: none;
|
||||
-webkit-user-select: none;
|
||||
-webkit-tap-highlight-color: rgb(0 0 0 / 0%);
|
||||
}
|
||||
|
||||
.tool-header .tool-header-text {
|
||||
font-size: 2.5rem;
|
||||
font-weight: 400;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
/* Home Card Colors*/
|
||||
.feature-card .nav-icon {
|
||||
vertical-align: middle;
|
||||
font-size: 2rem !important;
|
||||
padding: 0.75rem;
|
||||
border-radius: 0.9rem;
|
||||
color: var(--md-sys-color-surface);
|
||||
}
|
||||
|
||||
.feature-card .sign .nav-icon {
|
||||
color: var(--md-nav-on-section-color-sign);
|
||||
background-color: var(--md-nav-section-color-sign);
|
||||
}
|
||||
|
||||
.feature-card .organize .nav-icon {
|
||||
color: var(--md-nav-on-section-color-organize);
|
||||
background-color: var(--md-nav-section-color-organize);
|
||||
}
|
||||
|
||||
.feature-card .convert .nav-icon {
|
||||
color: var(--md-nav-on-section-color-convert);
|
||||
background-color: var(--md-nav-section-color-convert);
|
||||
}
|
||||
|
||||
.feature-card .convertto .nav-icon {
|
||||
color: var(--md-nav-on-section-color-convertto);
|
||||
background-color: var(--md-nav-section-color-convertto);
|
||||
}
|
||||
|
||||
.feature-card .security .nav-icon {
|
||||
color: var(--md-nav-on-section-color-security);
|
||||
background-color: var(--md-nav-section-color-security);
|
||||
}
|
||||
|
||||
.feature-card .other .nav-icon {
|
||||
color: var(--md-nav-on-section-color-other);
|
||||
background-color: var(--md-nav-section-color-other);
|
||||
}
|
||||
|
||||
.feature-card .advance .nav-icon {
|
||||
color: var(--md-nav-on-section-color-advance);
|
||||
background-color: var(--md-nav-section-color-advance);
|
||||
}
|
||||
|
||||
.feature-card .image .nav-icon {
|
||||
color: var(--md-nav-on-section-color-image);
|
||||
background-color: var(--md-nav-section-color-image);
|
||||
}
|
||||
|
||||
.feature-card .word .nav-icon {
|
||||
color: var(--md-nav-on-section-color-word);
|
||||
background-color: var(--md-nav-section-color-word);
|
||||
}
|
||||
|
||||
.feature-card .ppt .nav-icon {
|
||||
color: var(--md-nav-on-section-color-ppt);
|
||||
background-color: var(--md-nav-section-color-ppt);
|
||||
}
|
||||
|
||||
/* Buttons Components */
|
||||
.btn {
|
||||
border-radius: 1.25rem;
|
||||
}
|
||||
|
||||
.btn-close {
|
||||
width: auto;
|
||||
height: auto;
|
||||
color: var(--md-sys-color-on-surface);
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.btn-close:hover {
|
||||
color: var(--md-sys-color-on-surface);
|
||||
}
|
||||
|
||||
.modal-header .btn-close {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
/* Primary btn */
|
||||
.btn-primary {
|
||||
color: var(--md-sys-color-on-primary);
|
||||
background-color: var(--md-sys-color-primary);
|
||||
border-color: var(--md-sys-color-primary);
|
||||
box-shadow: none !important;
|
||||
}
|
||||
|
||||
.btn-primary.disabled,
|
||||
.btn-primary:disabled {
|
||||
color: var(--md-sys-color-on-primary);
|
||||
background-color: var(--md-sys-color-primary);
|
||||
border-color: var(--md-sys-color-primary);
|
||||
}
|
||||
|
||||
.btn-primary:hover {
|
||||
color: var(--md-sys-color-on-primary);
|
||||
background-color: var(--md-sys-color-primary);
|
||||
border-color: var(--md-sys-color-primary);
|
||||
box-shadow: var(--md-sys-elevation-3) !important;
|
||||
}
|
||||
|
||||
.btn-check:active+.btn-primary,
|
||||
.btn-check:checked+.btn-primary,
|
||||
.btn-primary.active,
|
||||
.btn-primary:active,
|
||||
.show>.btn-primary.dropdown-toggle {
|
||||
color: var(--md-sys-color-on-primary);
|
||||
background-color: var(--md-sys-color-primary);
|
||||
border-color: var(--md-sys-color-primary);
|
||||
box-shadow: var(--md-sys-elevation-3) !important;
|
||||
}
|
||||
|
||||
.btn-check:focus+.btn-primary,
|
||||
.btn-primary:focus {
|
||||
color: var(--md-sys-color-on-primary);
|
||||
background-color: var(--md-sys-color-primary);
|
||||
border-color: var(--md-sys-color-primary);
|
||||
box-shadow: var(--md-sys-elevation-3) !important;
|
||||
}
|
||||
|
||||
/* Secondary btn */
|
||||
.btn-secondary {
|
||||
color: var(--md-sys-color-on-secondary);
|
||||
background-color: var(--md-sys-color-secondary);
|
||||
border-color: var(--md-sys-color-secondary);
|
||||
box-shadow: none !important;
|
||||
}
|
||||
|
||||
.btn-secondary.disabled,
|
||||
.btn-secondary:disabled {
|
||||
color: var(--md-sys-color-on-secondary);
|
||||
background-color: var(--md-sys-color-secondary);
|
||||
border-color: var(--md-sys-color-secondary);
|
||||
}
|
||||
|
||||
.btn-secondary:hover {
|
||||
color: var(--md-sys-color-on-secondary);
|
||||
background-color: var(--md-sys-color-secondary);
|
||||
border-color: var(--md-sys-color-secondary);
|
||||
box-shadow: var(--md-sys-elevation-3) !important;
|
||||
}
|
||||
|
||||
.btn-check:active+.btn-secondary,
|
||||
.btn-check:checked+.btn-secondary,
|
||||
.btn-secondary.active,
|
||||
.btn-secondary:active,
|
||||
.show>.btn-secondary.dropdown-toggle {
|
||||
color: var(--md-sys-color-on-secondary);
|
||||
background-color: var(--md-sys-color-secondary);
|
||||
border-color: var(--md-sys-color-secondary);
|
||||
box-shadow: var(--md-sys-elevation-3) !important;
|
||||
}
|
||||
|
||||
.btn-check:focus+.btn-secondary,
|
||||
.btn-secondary:focus {
|
||||
color: var(--md-sys-color-on-secondary);
|
||||
background-color: var(--md-sys-color-secondary);
|
||||
border-color: var(--md-sys-color-secondary);
|
||||
box-shadow: var(--md-sys-elevation-3) !important;
|
||||
}
|
||||
|
||||
/* Danger btn */
|
||||
.btn-danger {
|
||||
color: var(--md-sys-color-on-error);
|
||||
background-color: var(--md-sys-color-error);
|
||||
border-color: var(--md-sys-color-error);
|
||||
box-shadow: none !important;
|
||||
}
|
||||
|
||||
.btn-danger.disabled,
|
||||
.btn-danger:disabled {
|
||||
color: var(--md-sys-color-on-error);
|
||||
background-color: var(--md-sys-color-error);
|
||||
border-color: var(--md-sys-color-error);
|
||||
}
|
||||
|
||||
.btn-danger:hover {
|
||||
color: var(--md-sys-color-on-error);
|
||||
background-color: var(--md-sys-color-error);
|
||||
border-color: var(--md-sys-color-error);
|
||||
box-shadow: var(--md-sys-elevation-3) !important;
|
||||
}
|
||||
|
||||
.btn-check:active+.btn-danger,
|
||||
.btn-check:checked+.btn-danger,
|
||||
.btn-danger.active,
|
||||
.btn-danger:active,
|
||||
.show>.btn-danger.dropdown-toggle {
|
||||
color: var(--md-sys-color-on-error);
|
||||
background-color: var(--md-sys-color-error);
|
||||
border-color: var(--md-sys-color-error);
|
||||
box-shadow: var(--md-sys-elevation-3) !important;
|
||||
}
|
||||
|
||||
.btn-check:focus+.btn-danger,
|
||||
.btn-danger:focus {
|
||||
color: var(--md-sys-color-on-error);
|
||||
background-color: var(--md-sys-color-error);
|
||||
border-color: var(--md-sys-color-error);
|
||||
box-shadow: var(--md-sys-elevation-3) !important;
|
||||
}
|
||||
|
||||
/* Info btn */
|
||||
.btn-info {
|
||||
color: var(--md-sys-color-on-tertiary);
|
||||
background-color: var(--md-sys-color-tertiary);
|
||||
border-color: var(--md-sys-color-tertiary);
|
||||
box-shadow: none !important;
|
||||
}
|
||||
|
||||
.btn-info .disabled,
|
||||
.btn-info:disabled {
|
||||
color: var(--md-sys-color-on-tertiary);
|
||||
background-color: var(--md-sys-color-tertiary);
|
||||
border-color: var(--md-sys-color-tertiary);
|
||||
}
|
||||
|
||||
.btn-info:hover {
|
||||
color: var(--md-sys-color-on-tertiary);
|
||||
background-color: var(--md-sys-color-tertiary);
|
||||
border-color: var(--md-sys-color-tertiary);
|
||||
box-shadow: var(--md-sys-elevation-3) !important;
|
||||
}
|
||||
|
||||
.btn-check:active+.btn-info,
|
||||
.btn-check:checked+.btn-info,
|
||||
.btn-info .active,
|
||||
.btn-info:active,
|
||||
.show>.btn-info.dropdown-toggle {
|
||||
color: var(--md-sys-color-on-tertiary);
|
||||
background-color: var(--md-sys-color-tertiary);
|
||||
border-color: var(--md-sys-color-tertiary);
|
||||
box-shadow: var(--md-sys-elevation-3) !important;
|
||||
}
|
||||
|
||||
.btn-check:focus+.btn-info,
|
||||
.btn-info:focus {
|
||||
color: var(--md-sys-color-on-tertiary);
|
||||
background-color: var(--md-sys-color-tertiary);
|
||||
border-color: var(--md-sys-color-tertiary);
|
||||
box-shadow: var(--md-sys-elevation-3) !important;
|
||||
}
|
||||
|
||||
/* Info btn */
|
||||
.btn-success {
|
||||
box-shadow: none !important;
|
||||
}
|
||||
|
||||
.btn-success:hover,
|
||||
.btn-check:active+.btn-success,
|
||||
.btn-check:checked+.btn-success,
|
||||
.btn-success .active,
|
||||
.btn-success:active,
|
||||
.show>.btn-success.dropdown-toggle,
|
||||
.btn-check:focus+.btn-success,
|
||||
.btn-success:focus {
|
||||
box-shadow: var(--md-sys-elevation-3) !important;
|
||||
}
|
||||
|
||||
/* Warning btn */
|
||||
.btn-warning {
|
||||
box-shadow: none !important;
|
||||
}
|
||||
|
||||
.btn-warning:hover,
|
||||
.btn-check:active+.btn-warning,
|
||||
.btn-check:checked+.btn-warning,
|
||||
.btn-warning .active,
|
||||
.btn-warning:active,
|
||||
.show>.btn-warning.dropdown-toggle,
|
||||
.btn-check:focus+.btn-warning,
|
||||
.btn-warning:focus {
|
||||
box-shadow: var(--md-sys-elevation-3) !important;
|
||||
}
|
||||
|
||||
/* Outline Primary btn */
|
||||
.btn-outline-primary {
|
||||
color: var(--md-sys-color-primary);
|
||||
background-color: transparent;
|
||||
border-color: var(--md-sys-color-primary);
|
||||
box-shadow: none !important;
|
||||
}
|
||||
|
||||
.btn-outline-primary .disabled,
|
||||
.btn-outline-primary:disabled {
|
||||
color: var(--md-sys-color-primary);
|
||||
background-color: transparent;
|
||||
border-color: var(--md-sys-color-primary);
|
||||
}
|
||||
|
||||
.btn-outline-primary:hover {
|
||||
color: var(--md-sys-color-on-primary);
|
||||
background-color: var(--md-sys-color-primary);
|
||||
border-color: var(--md-sys-color-primary);
|
||||
}
|
||||
|
||||
.btn-check:active+.btn-outline-primary,
|
||||
.btn-check:checked+.btn-outline-primary,
|
||||
.btn-outline-primary .active,
|
||||
.btn-outline-primary:active,
|
||||
.show>.btn-outline-primary.dropdown-toggle {
|
||||
color: var(--md-sys-color-on-primary);
|
||||
background-color: var(--md-sys-color-primary);
|
||||
border-color: var(--md-sys-color-primary);
|
||||
}
|
||||
|
||||
.btn-check:focus+.btn-outline-primary,
|
||||
.btn-outline-primary:focus {
|
||||
color: var(--md-sys-color-on-primary);
|
||||
background-color: var(--md-sys-color-primary);
|
||||
border-color: var(--md-sys-color-primary);
|
||||
}
|
||||
|
||||
/* Outline Secondary btn */
|
||||
.btn-outline-secondary {
|
||||
color: var(--md-sys-color-secondary);
|
||||
background-color: transparent;
|
||||
border-color: var(--md-sys-color-secondary);
|
||||
box-shadow: none !important;
|
||||
}
|
||||
|
||||
.btn-outline-secondary .disabled,
|
||||
.btn-outline-secondary:disabled {
|
||||
color: var(--md-sys-color-secondary);
|
||||
background-color: transparent;
|
||||
border-color: var(--md-sys-color-secondary);
|
||||
}
|
||||
|
||||
.btn-outline-secondary:hover {
|
||||
color: var(--md-sys-color-on-secondary);
|
||||
background-color: var(--md-sys-color-secondary);
|
||||
border-color: var(--md-sys-color-secondary);
|
||||
}
|
||||
|
||||
.btn-check:active+.btn-outline-secondary,
|
||||
.btn-check:checked+.btn-outline-secondary,
|
||||
.btn-outline-secondary .active,
|
||||
.btn-outline-secondary:active,
|
||||
.show>.btn-outline-secondary.dropdown-toggle {
|
||||
color: var(--md-sys-color-on-secondary);
|
||||
background-color: var(--md-sys-color-secondary);
|
||||
border-color: var(--md-sys-color-secondary);
|
||||
}
|
||||
|
||||
.btn-check:focus+.btn-outline-secondary,
|
||||
.btn-outline-secondary:focus {
|
||||
color: var(--md-sys-color-on-secondary);
|
||||
background-color: var(--md-sys-color-secondary);
|
||||
border-color: var(--md-sys-color-secondary);
|
||||
}
|
||||
|
||||
/* Disabled btn */
|
||||
.btn.disabled,
|
||||
.btn:disabled,
|
||||
fieldset:disabled .btn {
|
||||
pointer-events: none;
|
||||
opacity: 0.65;
|
||||
}
|
||||
|
||||
/* Range Slider */
|
||||
.form-range{
|
||||
margin-top: 0.25rem;
|
||||
}
|
||||
.form-range:focus::-webkit-slider-thumb {
|
||||
box-shadow: 0 0 0 1px var(--md-sys-color-surface), 0 0 0 .25rem var(--md-sys-color-primary)
|
||||
}
|
||||
|
||||
.form-range:focus::-moz-range-thumb {
|
||||
box-shadow: 0 0 0 1px var(--md-sys-color-surface), 0 0 0 .25rem var(--md-sys-color-primary)
|
||||
}
|
||||
|
||||
.form-range::-webkit-slider-thumb {
|
||||
background-color: var(--md-sys-color-primary);
|
||||
}
|
||||
|
||||
|
||||
.form-range::-webkit-slider-thumb:active {
|
||||
background-color: var(--md-sys-color-primary)
|
||||
}
|
||||
|
||||
.form-range::-webkit-slider-runnable-track {
|
||||
background-color: var(--md-sys-color-on-primary)
|
||||
}
|
||||
|
||||
.form-range::-moz-range-thumb {
|
||||
background-color: var(--md-sys-color-primary);
|
||||
}
|
||||
|
||||
|
||||
/* checkbox */
|
||||
.form-check {
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.form-check-label {
|
||||
margin-left: 0.5rem;
|
||||
margin-right: 0.5rem;
|
||||
}
|
||||
|
||||
.form-check-input {
|
||||
width: 1.5rem;
|
||||
height: 1.5rem;
|
||||
margin: 0;
|
||||
background-color: var(--md-sys-color-surface);
|
||||
border: 2px solid var(--md-sys-color-outline-variant);
|
||||
}
|
||||
|
||||
.form-check-input:checked {
|
||||
background-color: var(--md-sys-color-primary);
|
||||
border-color: var(--md-sys-color-outline-variant);
|
||||
border: none;
|
||||
}
|
||||
|
||||
.form-check-input:focus {
|
||||
border-color: var(--md-sys-color-outline-variant);
|
||||
outline: 0;
|
||||
box-shadow: 0 0 0 .25rem var(--md-sys-color-outline-variant);
|
||||
}
|
||||
|
||||
.form-check-input:checked[type=checkbox] {
|
||||
background-image: none;
|
||||
}
|
||||
|
||||
.form-check input[type="checkbox"]:checked+span.material-symbols-rounded {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.form-check span.material-symbols-rounded {
|
||||
display: none;
|
||||
color: var(--md-sys-color-surface);
|
||||
position: absolute;
|
||||
margin-left: -1.5rem;
|
||||
margin-right: -1.5rem;
|
||||
pointer-events: none;
|
||||
user-select: none;
|
||||
-webkit-user-select: none;
|
||||
-webkit-tap-highlight-color: rgb(0 0 0 / 0%);
|
||||
}
|
||||
|
||||
.form-check {
|
||||
min-height: 22px;
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
.form-check > label {
|
||||
padding-left: 29px !important;
|
||||
min-height: 22px;
|
||||
line-height: 22px;
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
vertical-align: top;
|
||||
margin-bottom: 0;
|
||||
font-weight: normal;
|
||||
cursor: pointer;
|
||||
padding-right: 29px !important;
|
||||
}
|
||||
|
||||
.form-check > input:first-child {
|
||||
position: absolute !important;
|
||||
opacity: 0;
|
||||
margin: 0;
|
||||
background-color: var(--md-sys-state-hover-opacity);
|
||||
border-radius: 50%;
|
||||
appearance: none;
|
||||
-moz-appearance: none;
|
||||
-webkit-appearance: none;
|
||||
-ms-appearance: none;
|
||||
display: block;
|
||||
width: 22px;
|
||||
height: 22px;
|
||||
outline: none;
|
||||
transform: scale(1.65);
|
||||
-ms-transform: scale(1.65);
|
||||
transition: opacity .3s;
|
||||
}
|
||||
|
||||
.form-check > input:first-child:hover {
|
||||
opacity: 1;
|
||||
transform: scale(1.65);
|
||||
-ms-transform: scale(1.65);
|
||||
}
|
||||
|
||||
.form-check > input:first-child:disabled {
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.form-check > input:first-child:disabled + label,
|
||||
.form-check > input:first-child:disabled + input[type="hidden"] + label,
|
||||
.form-check > input:first-child:disabled + label::before,
|
||||
.form-check > input:first-child:disabled + input[type="hidden"] + label::before {
|
||||
pointer-events: none;
|
||||
cursor: default;
|
||||
filter: alpha(opacity=65);
|
||||
-webkit-box-shadow: none;
|
||||
box-shadow: none;
|
||||
opacity: .65;
|
||||
}
|
||||
|
||||
.form-check > input:first-child + label::before,
|
||||
.form-check > input:first-child + input[type="hidden"] + label::before {
|
||||
content: "";
|
||||
display: inline-block;
|
||||
position: absolute;
|
||||
width: 22px;
|
||||
height: 22px;
|
||||
border: 2px solid var(--md-sys-color-on-surface-variant);
|
||||
border-radius: 3px;
|
||||
margin-left: -29px;
|
||||
box-sizing: border-box;
|
||||
margin-right: -29px;
|
||||
}
|
||||
|
||||
.form-check > input:first-child:checked + label::after,
|
||||
.form-check > input:first-child:checked + input[type="hidden"] + label::after {
|
||||
content: "";
|
||||
display: inline-block;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 7px;
|
||||
height: 10px;
|
||||
border: solid 2px;
|
||||
border-left: none;
|
||||
border-top: none;
|
||||
transform: translate(7.75px, 4.5px) rotate(45deg);
|
||||
-ms-transform: translate(7.75px, 4.5px) rotate(45deg);
|
||||
box-sizing: border-box;
|
||||
right: 0;
|
||||
margin-right: 14px;
|
||||
border-bottom-color: var(--md-sys-color-on-primary);
|
||||
border-right-color: var(--md-sys-color-on-primary);
|
||||
}
|
||||
|
||||
.form-check > input:first-child::-ms-check {
|
||||
opacity: 0;
|
||||
border-radius: 50%;
|
||||
background-color: var(--md-sys-color-primary);
|
||||
}
|
||||
|
||||
.form-check > input:first-child:active {
|
||||
transform: scale(0);
|
||||
-ms-transform: scale(0);
|
||||
opacity: 1;
|
||||
transition: opacity 0s, transform 0s;
|
||||
}
|
||||
|
||||
.form-check > input[type="radio"]:first-child + label::before,
|
||||
.form-check > input[type="radio"]:first-child + input[type="hidden"] + label::before {
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.form-check > input[type="radio"]:first-child:checked + label::before,
|
||||
.form-check > input[type="radio"]:first-child:checked + input[type="hidden"] + label::before {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.form-check > input[type="radio"]:first-child:checked + label::after,
|
||||
.form-check > input[type="radio"]:first-child:checked + input[type="hidden"] + label::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
border-radius: 50%;
|
||||
border: none;
|
||||
top: 6px;
|
||||
left: 6px;
|
||||
transform: none;
|
||||
-ms-transform: none;
|
||||
}
|
||||
|
||||
.form-check > input[type="checkbox"]:first-child:checked + label::after,
|
||||
.form-check > input[type="checkbox"]:first-child:checked + input[type="hidden"] + label::after {
|
||||
width: 8px;
|
||||
height: 14px;
|
||||
transform: translate(7px, 2px) rotate(45deg);
|
||||
-ms-transform: translate(7px, 2px) rotate(45deg);
|
||||
}
|
||||
|
||||
.form-check-inline {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.form-check-inline + .form-check-inline {
|
||||
margin-left: .75rem;
|
||||
margin-top: 6px;
|
||||
}
|
||||
|
||||
.form-check > input:first-child:checked + label::before,
|
||||
.form-check > input:first-child:checked + input[type="hidden"] + label::before {
|
||||
background-color: var(--md-sys-color-primary);
|
||||
border-color: var(--md-sys-color-primary);
|
||||
}
|
||||
|
||||
/* Forms */
|
||||
textarea.form-control {
|
||||
border-radius: 1.5rem !important;
|
||||
}
|
||||
|
||||
.form-control,
|
||||
.form-select,
|
||||
.form-control:disabled,
|
||||
.form-control[readonly] {
|
||||
color: var(--md-sys-color-on-surface);
|
||||
background-color: var(--md-sys-color-surface-container-low);
|
||||
border-color: var(--md-sys-color-outline-variant);
|
||||
border-radius: 3rem !important;
|
||||
}
|
||||
|
||||
.form-control:focus,
|
||||
.form-select:focus {
|
||||
color: var(--md-sys-color-on-surface);
|
||||
background-color: var(--md-sys-color-surface-container-lowest);
|
||||
border-color: var(--md-sys-color-outline-variant);
|
||||
outline: 0;
|
||||
box-shadow: 0 0 0 0.25rem var(--md-sys-color-outline-variant);
|
||||
}
|
||||
|
||||
.form-control-color {
|
||||
padding: 0;
|
||||
height: 2.4rem;
|
||||
width: 2.4rem;
|
||||
}
|
||||
|
||||
.form-control input[type="color"] {
|
||||
opacity: 0;
|
||||
height: 2.4rem;
|
||||
width: 2.4rem;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.form-control input[type="color"]:hover{
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
/* Navbar Components */
|
||||
.navbar-brand {
|
||||
color: var(--md-sys-color-on-surface) !important;
|
||||
}
|
||||
|
||||
.nav-link {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
transition: none !important;
|
||||
padding: 0.5rem 1rem !important;
|
||||
border: 1px transparent;
|
||||
}
|
||||
|
||||
.navbar-nav li {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.navbar-nav .nav-link {
|
||||
color: var(--md-sys-color-on-surface-variant);
|
||||
}
|
||||
|
||||
.navbar-nav .nav-link:focus,
|
||||
.navbar-nav .nav-link:hover {
|
||||
color: var(--md-sys-color-on-secondary-container);
|
||||
background-color: var(--md-sys-color-surface-3);
|
||||
border-radius: 3rem;
|
||||
font-weight: 500;
|
||||
font-variation-settings: var(--md-sys-icon-fill-1);
|
||||
}
|
||||
|
||||
.navbar-nav .nav-link.active,
|
||||
.navbar-nav .show>.nav-link {
|
||||
color: var(--md-sys-color-on-secondary-container);
|
||||
background-color: var(--md-sys-color-surface-5);
|
||||
border-radius: 3rem;
|
||||
font-weight: 500;
|
||||
font-variation-settings: var(--md-sys-icon-fill-1);
|
||||
}
|
||||
|
||||
.menu-title {
|
||||
padding: 0 1rem;
|
||||
}
|
||||
|
||||
.dropdown-menu {
|
||||
margin: 0 1%;
|
||||
padding: 1.5rem 0;
|
||||
border-radius: 1rem;
|
||||
min-width: 20rem;
|
||||
color: var(--md-sys-color-on-surface);
|
||||
background-color: var(--md-sys-color-surface-container);
|
||||
border: 1px solid var(--md-sys-color-surface-5);
|
||||
box-shadow: var(--md-sys-elevation-2);
|
||||
}
|
||||
|
||||
.dropdown-item {
|
||||
color: var(--md-sys-color-on-surface);
|
||||
padding: 0.25rem 1rem;
|
||||
border-radius: 3rem;
|
||||
|
||||
}
|
||||
|
||||
.dropdown-item:focus,
|
||||
.dropdown-item:hover {
|
||||
color: var(--md-sys-color-on-surface);
|
||||
background-color: var(--md-sys-color-surface-5);
|
||||
border-radius: 3rem;
|
||||
font-variation-settings: var(--md-sys-icon-fill-1);
|
||||
}
|
||||
.dropdown-item.no-hover:hover,
|
||||
.dropdown-item.no-hover:focus {
|
||||
color: var(--md-sys-color-on-surface) !important;
|
||||
background-color: transparent !important;
|
||||
border-radius: 3rem !important;
|
||||
font-variation-settings: initial !important;
|
||||
}
|
||||
|
||||
.dropdown-item.active,
|
||||
.dropdown-item:active {
|
||||
color: var(--md-sys-color-on-surface);
|
||||
background-color: var(--md-sys-color-surface-5);
|
||||
border-radius: 3rem;
|
||||
font-weight: 500;
|
||||
font-variation-settings: var(--md-sys-icon-fill-1);
|
||||
}
|
||||
|
||||
/* list-group-item */
|
||||
.list-group-item {
|
||||
color: var(--md-sys-color-on-surface);
|
||||
background-color: var(--md-sys-color-surface-5);
|
||||
border: 1px solid var(--md-sys-color-outline-variant);
|
||||
}
|
||||
|
||||
.list-group-item:first-child {
|
||||
border-radius: 1rem 1rem 0rem 0rem;
|
||||
}
|
||||
|
||||
.list-group-item:last-child {
|
||||
border-radius: 0rem 0rem 1rem 1rem;
|
||||
}
|
||||
|
||||
.list-group-item:only-child {
|
||||
border-radius: 1rem 1rem 1rem 1rem;
|
||||
}
|
||||
|
||||
.list-group-item .btn {
|
||||
padding: .375rem .5rem;
|
||||
}
|
||||
|
||||
/*Alert */
|
||||
.alert-container {
|
||||
padding: 2rem 3rem;
|
||||
border-radius: 3rem;
|
||||
margin: 1rem 0rem 2rem;
|
||||
}
|
||||
|
||||
.alert-header {
|
||||
display: flex !important;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.alert-heading {
|
||||
font-size: calc(1.275rem + .3vw);
|
||||
}
|
||||
|
||||
.alert-dismissible .btn-close {
|
||||
position: relative;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.alert-danger {
|
||||
color: var(--md-sys-color-on-error-container);
|
||||
background-color: var(--md-sys-color-error-container);
|
||||
border-color: transparent;
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
@font-face {
|
||||
font-family: 'Material Symbols Rounded';
|
||||
font-style: normal;
|
||||
font-weight: 100 700;
|
||||
src: url(../../fonts/google-symbol.woff2) format('woff2');
|
||||
}
|
||||
|
||||
|
||||
|
||||
.material-symbols-rounded {
|
||||
font-family: 'Material Symbols Rounded';
|
||||
font-weight: 300;
|
||||
font-style: normal;
|
||||
font-size: 24px;
|
||||
line-height: 1;
|
||||
letter-spacing: normal;
|
||||
text-transform: none;
|
||||
display: inline-block;
|
||||
white-space: nowrap;
|
||||
word-wrap: normal;
|
||||
direction: ltr;
|
||||
-webkit-font-feature-settings: 'liga';
|
||||
-webkit-font-smoothing: antialiased;
|
||||
}
|
||||
@@ -1,42 +0,0 @@
|
||||
:where(html, .light-theme, .dark-theme),
|
||||
.tokens,
|
||||
:host {
|
||||
/* Define surface colors based on primary color */
|
||||
--md-sys-color-surface-1: color-mix(in srgb, var(--md-sys-color-primary) 13%, rgba(0, 0, 100, 0.05) 5%);
|
||||
--md-sys-color-surface-2: color-mix(in srgb, var(--md-sys-color-primary) 13%, rgba(0, 0, 255, 0.08) 5%);
|
||||
--md-sys-color-surface-3: color-mix(in srgb, var(--md-sys-color-primary) 13%, rgba(0, 0, 255, 0.11) 5%);
|
||||
--md-sys-color-surface-4: color-mix(in srgb, var(--md-sys-color-primary) 13%, rgba(0, 0, 255, 0.12) 5%);
|
||||
--md-sys-color-surface-5: color-mix(in srgb, var(--md-sys-color-primary) 13%, rgba(0, 0, 255, 0.14) 5%);
|
||||
/* Clear button disabled text color (default/light) */
|
||||
--spdf-clear-disabled-text: var(--md-sys-color-primary);
|
||||
/* Icon fill */
|
||||
--md-sys-icon-fill-0: 'FILL' 0, 'wght' 500;
|
||||
--md-sys-icon-fill-1: 'FILL' 1, 'wght' 500;
|
||||
/* Hover Color */
|
||||
--md-sys-state-hover-opacity: color-mix(in srgb, var(--md-sys-color-primary), rgba(0, 0, 0, 0) 80%);
|
||||
/* Shadow */
|
||||
--md-sys-color-shadow: #000000;
|
||||
--md-elevation-shadow-color-rgb: 0, 0, 0;
|
||||
--md-elevation-shadow-color: var(--md-elevation-shadow-color-rgb);
|
||||
/* Shadow Elevation*/
|
||||
--md-sys-elevation-0: 0px 0px 0px 0px rgb(var(--md-elevation-shadow-color), 0.2), 0px 0px 0px 0px rgb(var(--md-elevation-shadow-color), 0.14), 0px 0px 0px 0px rgb(var(--md-elevation-shadow-color), 0.12);
|
||||
--md-sys-elevation-1: 0px 3px 1px -2px rgb(var(--md-elevation-shadow-color), 0.2), 0px 2px 2px 0px rgb(var(--md-elevation-shadow-color), 0.14), 0px 1px 5px 0px rgb(var(--md-elevation-shadow-color), 0.12);
|
||||
--md-sys-elevation-2: 0px 2px 4px -1px rgb(var(--md-elevation-shadow-color), 0.2), 0px 4px 5px 0px rgb(var(--md-elevation-shadow-color), 0.14), 0px 1px 10px 0px rgb(var(--md-elevation-shadow-color), 0.12);
|
||||
--md-sys-elevation-3: 0px 5px 5px -3px rgb(var(--md-elevation-shadow-color), 0.2), 0px 8px 10px 1px rgb(var(--md-elevation-shadow-color), 0.14), 0px 3px 14px 2px rgb(var(--md-elevation-shadow-color), 0.12);
|
||||
--md-sys-elevation-4: 0px 5px 5px -3px rgb(var(--md-elevation-shadow-color) / 0.2), 0px 8px 10px 1px rgb(var(--md-elevation-shadow-color), 0.14), 0px 3px 14px 2px rgb(var(--md-elevation-shadow-color), 0.12);
|
||||
--md-sys-elevation-5: 0px 8px 10px -6px rgb(var(--md-elevation-shadow-color), 0.2), 0px 16px 24px 2px rgb(var(--md-elevation-shadow-color), 0.14), 0px 6px 30px 5px rgb(var(--md-elevation-shadow-color), 0.12);
|
||||
}
|
||||
|
||||
/* Dark theme overrides */
|
||||
.dark-theme {
|
||||
/* In dark mode, use a neutral grey for disabled Clear button text */
|
||||
--spdf-clear-disabled-text: var(--mantine-color-gray-5, #9e9e9e);
|
||||
}
|
||||
|
||||
.fill {
|
||||
font-variation-settings: var(--md-sys-icon-fill-1);
|
||||
}
|
||||
|
||||
.no-fill {
|
||||
/* font-variation-settings: var(--md-sys-icon-fill-0); */
|
||||
}
|
||||
@@ -1,79 +0,0 @@
|
||||
:root {
|
||||
/* Colors */
|
||||
--md-sys-color-primary: rgb(162 201 255);
|
||||
--md-sys-color-surface-tint: rgb(162 201 255);
|
||||
--md-sys-color-on-primary: rgb(0 49 92);
|
||||
--md-sys-color-primary-container: rgb(0 118 208);
|
||||
--md-sys-color-on-primary-container: rgb(255 255 255);
|
||||
--md-sys-color-secondary: rgb(169 201 246);
|
||||
--md-sys-color-on-secondary: rgb(12 49 87);
|
||||
--md-sys-color-secondary-container: rgb(29 62 100);
|
||||
--md-sys-color-on-secondary-container: rgb(180 210 255);
|
||||
--md-sys-color-tertiary: rgb(193 194 248);
|
||||
--md-sys-color-on-tertiary: rgb(42 44 88);
|
||||
--md-sys-color-tertiary-container: rgb(110 112 161);
|
||||
--md-sys-color-on-tertiary-container: rgb(255 255 255);
|
||||
--md-sys-color-error: rgb(255 180 171);
|
||||
--md-sys-color-on-error: rgb(105 0 5);
|
||||
--md-sys-color-error-container: rgb(147 0 10);
|
||||
--md-sys-color-on-error-container: rgb(255 218 214);
|
||||
--md-sys-color-background: rgb(15 20 26);
|
||||
--md-sys-color-on-background: rgb(223 226 235);
|
||||
--md-sys-color-surface: rgb(15 20 26);
|
||||
--md-sys-color-on-surface: rgb(223 226 235);
|
||||
--md-sys-color-surface-variant: rgb(64 71 83);
|
||||
--md-sys-color-on-surface-variant: rgb(192 199 213);
|
||||
--md-sys-color-outline: rgb(138 145 158);
|
||||
--md-sys-color-outline-variant: rgb(64 71 83);
|
||||
--md-sys-color-shadow: rgb(0 0 0);
|
||||
--md-sys-color-scrim: rgb(0 0 0);
|
||||
--md-sys-color-inverse-surface: rgb(223 226 235);
|
||||
--md-sys-color-inverse-on-surface: rgb(45 49 55);
|
||||
--md-sys-color-inverse-primary: rgb(0 96 170);
|
||||
--md-sys-color-primary-fixed: rgb(211 228 255);
|
||||
--md-sys-color-on-primary-fixed: rgb(0 28 56);
|
||||
--md-sys-color-primary-fixed-dim: rgb(162 201 255);
|
||||
--md-sys-color-on-primary-fixed-variant: rgb(0 72 130);
|
||||
--md-sys-color-secondary-fixed: rgb(211 228 255);
|
||||
--md-sys-color-on-secondary-fixed: rgb(0 28 56);
|
||||
--md-sys-color-secondary-fixed-dim: rgb(169 201 246);
|
||||
--md-sys-color-on-secondary-fixed-variant: rgb(40 72 111);
|
||||
--md-sys-color-tertiary-fixed: rgb(225 224 255);
|
||||
--md-sys-color-on-tertiary-fixed: rgb(20 22 66);
|
||||
--md-sys-color-tertiary-fixed-dim: rgb(193 194 248);
|
||||
--md-sys-color-on-tertiary-fixed-variant: rgb(64 67 112);
|
||||
--md-sys-color-surface-dim: rgb(15 20 26);
|
||||
--md-sys-color-surface-bright: rgb(53 57 64);
|
||||
--md-sys-color-surface-container-lowest: rgb(10 14 20);
|
||||
--md-sys-color-surface-container-low: rgb(24 28 34);
|
||||
--md-sys-color-surface-container: rgb(28 32 38);
|
||||
--md-sys-color-surface-container-high: rgb(38 42 49);
|
||||
--md-sys-color-surface-container-highest: rgb(49 53 60);
|
||||
/* Tools Color */
|
||||
--md-nav-section-color-opacity: 1;
|
||||
--md-nav-on-section-color-opacity: 1;
|
||||
--md-nav-section-color-sign: rgba(25, 101, 212, var(--md-nav-section-color-opacity));
|
||||
--md-nav-on-section-color-sign: rgba(28, 27, 31, var(--md-nav-on-section-color-opacity));
|
||||
--md-nav-section-color-organize: rgba(120, 130, 255, var(--md-nav-section-color-opacity));
|
||||
--md-nav-on-section-color-organize: rgba(28, 27, 31, var(--md-nav-on-section-color-opacity));
|
||||
--md-nav-section-color-convert: rgba(25, 177, 212, var(--md-nav-section-color-opacity));
|
||||
--md-nav-on-section-color-convert: rgba(28, 27, 31, var(--md-nav-on-section-color-opacity));
|
||||
--md-nav-section-color-convertto: rgba(104, 220, 149, var(--md-nav-section-color-opacity));
|
||||
--md-nav-on-section-color-convertto: rgba(28, 27, 31, var(--md-nav-on-section-color-opacity));
|
||||
--md-nav-section-color-security: rgba(255, 120, 146, var(--md-nav-section-color-opacity));
|
||||
--md-nav-on-section-color-security: rgba(28, 27, 31, var(--md-nav-on-section-color-opacity));
|
||||
--md-nav-section-color-other: rgba(72, 189, 84, var(--md-nav-section-color-opacity));
|
||||
--md-nav-on-section-color-other: rgba(28, 27, 31, var(--md-nav-on-section-color-opacity));
|
||||
--md-nav-section-color-advance: rgba(245, 84, 84, var(--md-nav-section-color-opacity));
|
||||
--md-nav-on-section-color-advance: rgba(28, 27, 31, var(--md-nav-on-section-color-opacity));
|
||||
--md-nav-section-color-image: rgba(212, 172, 25, var(--md-nav-section-color-opacity));
|
||||
--md-nav-on-section-color-image: rgba(28, 27, 31, var(--md-nav-on-section-color-opacity));
|
||||
--md-nav-section-color-word: rgba(61, 153, 245, var(--md-nav-section-color-opacity));
|
||||
--md-nav-on-section-color-word: rgba(28, 27, 31, var(--md-nav-on-section-color-opacity));
|
||||
--md-nav-section-color-ppt: rgba(255, 128, 0, var(--md-nav-section-color-opacity));
|
||||
--md-nav-on-section-color-ppt: rgba(28, 27, 31, var(--md-nav-on-section-color-opacity));
|
||||
--md-nav-color-on-separator: rgb(24 28 34);
|
||||
--md-nav-background: rgb(15 20 26);
|
||||
--favourite-add: #9ed18c;
|
||||
--favourite-remove: palevioletred;
|
||||
}
|
||||
@@ -1,79 +0,0 @@
|
||||
:root {
|
||||
/* Colors */
|
||||
--md-sys-color-primary: rgb(0 96 170);
|
||||
--md-sys-color-surface-tint: rgb(0 96 170);
|
||||
--md-sys-color-on-primary: rgb(255 255 255);
|
||||
--md-sys-color-primary-container: rgb(80 163 255);
|
||||
--md-sys-color-on-primary-container: rgb(0 20 43);
|
||||
--md-sys-color-secondary: rgb(65 96 136);
|
||||
--md-sys-color-on-secondary: rgb(255 255 255);
|
||||
--md-sys-color-secondary-container: rgb(188 215 255);
|
||||
--md-sys-color-on-secondary-container: rgb(32 65 103);
|
||||
--md-sys-color-tertiary: rgb(88 90 138);
|
||||
--md-sys-color-on-tertiary: rgb(255 255 255);
|
||||
--md-sys-color-tertiary-container: rgb(151 153 205);
|
||||
--md-sys-color-on-tertiary-container: rgb(7 9 55);
|
||||
--md-sys-color-error: rgb(186 26 26);
|
||||
--md-sys-color-on-error: rgb(255 255 255);
|
||||
--md-sys-color-error-container: rgb(255 218 214);
|
||||
--md-sys-color-on-error-container: rgb(65 0 2);
|
||||
--md-sys-color-background: rgb(248 249 255);
|
||||
--md-sys-color-on-background: rgb(24 28 34);
|
||||
--md-sys-color-surface: rgb(237, 240, 245);
|
||||
--md-sys-color-on-surface: rgb(0, 1, 1);
|
||||
--md-sys-color-surface-variant: rgb(220 227 241);
|
||||
--md-sys-color-on-surface-variant: rgb(64 71 83);
|
||||
--md-sys-color-outline: rgb(112 119 132);
|
||||
--md-sys-color-outline-variant: rgb(192 199 213);
|
||||
--md-sys-color-shadow: rgb(0 0 0);
|
||||
--md-sys-color-scrim: rgb(0 0 0);
|
||||
--md-sys-color-inverse-surface: rgb(45 49 55);
|
||||
--md-sys-color-inverse-on-surface: rgb(238 241 250);
|
||||
--md-sys-color-inverse-primary: rgb(162 201 255);
|
||||
--md-sys-color-primary-fixed: rgb(211 228 255);
|
||||
--md-sys-color-on-primary-fixed: rgb(0 28 56);
|
||||
--md-sys-color-primary-fixed-dim: rgb(162 201 255);
|
||||
--md-sys-color-on-primary-fixed-variant: rgb(0 72 130);
|
||||
--md-sys-color-secondary-fixed: rgb(211 228 255);
|
||||
--md-sys-color-on-secondary-fixed: rgb(0 28 56);
|
||||
--md-sys-color-secondary-fixed-dim: rgb(169 201 246);
|
||||
--md-sys-color-on-secondary-fixed-variant: rgb(40 72 111);
|
||||
--md-sys-color-tertiary-fixed: rgb(225 224 255);
|
||||
--md-sys-color-on-tertiary-fixed: rgb(20 22 66);
|
||||
--md-sys-color-tertiary-fixed-dim: rgb(193 194 248);
|
||||
--md-sys-color-on-tertiary-fixed-variant: rgb(64 67 112);
|
||||
--md-sys-color-surface-dim: rgb(215 218 227);
|
||||
--md-sys-color-surface-bright: rgb(248 249 255);
|
||||
--md-sys-color-surface-container-lowest: rgb(255 255 255);
|
||||
--md-sys-color-surface-container-low: rgb(241 243 253);
|
||||
--md-sys-color-surface-container: rgb(235 238 247);
|
||||
--md-sys-color-surface-container-high: rgb(229 232 241);
|
||||
--md-sys-color-surface-container-highest: rgb(223 226 235);
|
||||
/* Tools Color */
|
||||
--md-nav-section-color-opacity: 1;
|
||||
--md-nav-on-section-color-opacity: 1;
|
||||
--md-nav-section-color-sign: rgba(25, 101, 212, var(--md-nav-section-color-opacity));
|
||||
--md-nav-on-section-color-sign: rgba(255, 251, 254, var(--md-nav-on-section-color-opacity));
|
||||
--md-nav-section-color-organize: rgba(120, 130, 255, var(--md-nav-section-color-opacity));
|
||||
--md-nav-on-section-color-organize: rgba(255, 251, 254, var(--md-nav-on-section-color-opacity));
|
||||
--md-nav-section-color-convert: rgba(25, 177, 212, var(--md-nav-section-color-opacity));
|
||||
--md-nav-on-section-color-convert: rgba(255, 251, 254, var(--md-nav-on-section-color-opacity));
|
||||
--md-nav-section-color-convertto: rgba(104, 220, 149, var(--md-nav-section-color-opacity));
|
||||
--md-nav-on-section-color-convertto: rgba(255, 251, 254, var(--md-nav-on-section-color-opacity));
|
||||
--md-nav-section-color-security: rgba(255, 120, 146, var(--md-nav-section-color-opacity));
|
||||
--md-nav-on-section-color-security: rgba(255, 251, 254, var(--md-nav-on-section-color-opacity));
|
||||
--md-nav-section-color-other: rgba(72, 189, 84, var(--md-nav-section-color-opacity));
|
||||
--md-nav-on-section-color-other: rgba(255, 251, 254, var(--md-nav-on-section-color-opacity));
|
||||
--md-nav-section-color-advance: rgba(245, 84, 84, var(--md-nav-section-color-opacity));
|
||||
--md-nav-on-section-color-advance: rgba(255, 251, 254, var(--md-nav-on-section-color-opacity));
|
||||
--md-nav-section-color-image: rgba(212, 172, 25, var(--md-nav-section-color-opacity));
|
||||
--md-nav-on-section-color-image: rgba(255, 251, 254, var(--md-nav-on-section-color-opacity));
|
||||
--md-nav-section-color-word: rgba(61, 153, 245, var(--md-nav-section-color-opacity));
|
||||
--md-nav-on-section-color-word: rgba(255, 251, 254, var(--md-nav-on-section-color-opacity));
|
||||
--md-nav-section-color-ppt: rgba(255, 128, 0, var(--md-nav-section-color-opacity));
|
||||
--md-nav-on-section-color-ppt: rgba(255, 251, 254, var(--md-nav-on-section-color-opacity));
|
||||
--md-nav-color-on-separator: rgb(174, 178, 179);
|
||||
--md-nav-background: rgb(248 249 255);
|
||||
--favourite-add: #25ab6c;
|
||||
--favourite-remove: rgb(222, 94, 137);
|
||||
}
|
||||
@@ -1,96 +0,0 @@
|
||||
package stirling.software.SPDF.controller.api;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.CsvSource;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
|
||||
import stirling.software.common.service.CustomPDFDocumentFactory;
|
||||
|
||||
@ExtendWith({MockitoExtension.class})
|
||||
class RearrangePagesPDFControllerTest {
|
||||
|
||||
@Mock private CustomPDFDocumentFactory mockPdfDocumentFactory;
|
||||
|
||||
private RearrangePagesPDFController sut;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
sut = new RearrangePagesPDFController(mockPdfDocumentFactory);
|
||||
}
|
||||
|
||||
/** Tests the behavior of the oddEvenMerge method when there are no pages in the document. */
|
||||
@Test
|
||||
void oddEvenMerge_noPages() {
|
||||
int totalNumberOfPages = 0;
|
||||
|
||||
List<Integer> newPageOrder = sut.oddEvenMerge(totalNumberOfPages);
|
||||
|
||||
assertNotNull(newPageOrder, "Returning null instead of page order list");
|
||||
assertEquals(List.of(), newPageOrder, "Page order doesn't match");
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the behavior of the oddEvenMerge method when there are odd total pages in the document.
|
||||
*/
|
||||
@Test
|
||||
void oddEvenMerge_oddTotalPageNumber() {
|
||||
int totalNumberOfPages = 5;
|
||||
|
||||
List<Integer> newPageOrder = sut.oddEvenMerge(totalNumberOfPages);
|
||||
|
||||
assertNotNull(newPageOrder, "Returning null instead of page order list");
|
||||
assertEquals(Arrays.asList(0, 3, 1, 4, 2), newPageOrder, "Page order doesn't match");
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the behavior of the oddEvenMerge method when there are even total pages in the
|
||||
* document.
|
||||
*/
|
||||
@Test
|
||||
void oddEvenMerge_evenTotalPageNumber() {
|
||||
int totalNumberOfPages = 6;
|
||||
|
||||
List<Integer> newPageOrder = sut.oddEvenMerge(totalNumberOfPages);
|
||||
|
||||
assertNotNull(newPageOrder, "Returning null instead of page order list");
|
||||
assertEquals(Arrays.asList(0, 3, 1, 4, 2, 5), newPageOrder, "Page order doesn't match");
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the behavior of the oddEvenMerge method with multiple test cases of multiple pages.
|
||||
*
|
||||
* @param totalNumberOfPages The total number of pages in the document.
|
||||
* @param expectedPageOrder The expected order of the pages after rearranging.
|
||||
*/
|
||||
@ParameterizedTest
|
||||
@CsvSource({
|
||||
"1, '0'",
|
||||
"2, '0,1'",
|
||||
"3, '0,2,1'",
|
||||
"4, '0,2,1,3'",
|
||||
"5, '0,3,1,4,2'",
|
||||
"6, '0,3,1,4,2,5'",
|
||||
"10, '0,5,1,6,2,7,3,8,4,9'",
|
||||
"50, '0,25,1,26,2,27,3,28,4,29,5,30,6,31,7,32,8,33,9,34,10,35,"
|
||||
+ "11,36,12,37,13,38,14,39,15,40,16,41,17,42,18,43,19,44,20,45,21,46,"
|
||||
+ "22,47,23,48,24,49'"
|
||||
})
|
||||
void oddEvenMerge_multi_test(int totalNumberOfPages, String expectedPageOrder) {
|
||||
List<Integer> newPageOrder = sut.oddEvenMerge(totalNumberOfPages);
|
||||
|
||||
assertNotNull(newPageOrder, "Returning null instead of page order list");
|
||||
assertEquals(
|
||||
Arrays.stream(expectedPageOrder.split(",")).map(Integer::parseInt).toList(),
|
||||
newPageOrder,
|
||||
"Page order doesn't match");
|
||||
}
|
||||
}
|
||||
@@ -20,7 +20,6 @@ class SortTypesTest {
|
||||
"BOOKLET_SORT",
|
||||
"SIDE_STITCH_BOOKLET_SORT",
|
||||
"ODD_EVEN_SPLIT",
|
||||
"ODD_EVEN_MERGE",
|
||||
"REMOVE_FIRST",
|
||||
"REMOVE_LAST",
|
||||
"REMOVE_FIRST_AND_LAST",
|
||||
|
||||
@@ -1,146 +0,0 @@
|
||||
package stirling.software.SPDF.service;
|
||||
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
|
||||
import org.apache.pdfbox.cos.COSName;
|
||||
import org.apache.pdfbox.pdmodel.PDDocument;
|
||||
import org.apache.pdfbox.pdmodel.PDPage;
|
||||
import org.apache.pdfbox.pdmodel.PDPageTree;
|
||||
import org.apache.pdfbox.pdmodel.PDResources;
|
||||
import org.apache.pdfbox.pdmodel.graphics.PDXObject;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.mockito.Mockito;
|
||||
|
||||
class PdfImageRemovalServiceTest {
|
||||
|
||||
private PdfImageRemovalService service;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
service = new PdfImageRemovalService();
|
||||
}
|
||||
|
||||
// Helper method for matching COSName in verification
|
||||
private static COSName eq(final COSName value) {
|
||||
return Mockito.argThat(
|
||||
new org.mockito.ArgumentMatcher<>() {
|
||||
@Override
|
||||
public boolean matches(COSName argument) {
|
||||
if (argument == null && value == null) return true;
|
||||
if (argument == null || value == null) return false;
|
||||
return argument.getName().equals(value.getName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "eq(" + (value != null ? value.getName() : "null") + ")";
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void testRemoveImagesFromPdf_WithImages() throws IOException {
|
||||
// Mock PDF document and its components
|
||||
PDDocument document = mock(PDDocument.class);
|
||||
PDPage page = mock(PDPage.class);
|
||||
PDResources resources = mock(PDResources.class);
|
||||
PDPageTree pageTree = mock(PDPageTree.class);
|
||||
|
||||
// Configure page tree to iterate over our single page
|
||||
when(document.getPages()).thenReturn(pageTree);
|
||||
Iterator<PDPage> pageIterator = Collections.singletonList(page).iterator();
|
||||
when(pageTree.iterator()).thenReturn(pageIterator);
|
||||
|
||||
// Set up page resources
|
||||
when(page.getResources()).thenReturn(resources);
|
||||
|
||||
// Set up image XObjects
|
||||
COSName img1 = COSName.getPDFName("Im1");
|
||||
COSName img2 = COSName.getPDFName("Im2");
|
||||
COSName nonImg = COSName.getPDFName("NonImg");
|
||||
|
||||
List<COSName> xObjectNames = Arrays.asList(img1, img2, nonImg);
|
||||
when(resources.getXObjectNames()).thenReturn(xObjectNames);
|
||||
|
||||
// Configure which are image XObjects
|
||||
when(resources.isImageXObject(img1)).thenReturn(true);
|
||||
when(resources.isImageXObject(img2)).thenReturn(true);
|
||||
when(resources.isImageXObject(nonImg)).thenReturn(false);
|
||||
|
||||
// Execute the method
|
||||
service.removeImagesFromPdf(document);
|
||||
|
||||
// Verify that images were removed
|
||||
verify(resources, times(1)).put(eq(img1), Mockito.<PDXObject>isNull());
|
||||
verify(resources, times(1)).put(eq(img2), Mockito.<PDXObject>isNull());
|
||||
verify(resources, never()).put(eq(nonImg), Mockito.<PDXObject>isNull());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testRemoveImagesFromPdf_NoImages() throws IOException {
|
||||
// Mock PDF document and its components
|
||||
PDDocument document = mock(PDDocument.class);
|
||||
PDPage page = mock(PDPage.class);
|
||||
PDResources resources = mock(PDResources.class);
|
||||
PDPageTree pageTree = mock(PDPageTree.class);
|
||||
|
||||
// Configure page tree to iterate over our single page
|
||||
when(document.getPages()).thenReturn(pageTree);
|
||||
Iterator<PDPage> pageIterator = Collections.singletonList(page).iterator();
|
||||
when(pageTree.iterator()).thenReturn(pageIterator);
|
||||
|
||||
// Set up page resources
|
||||
when(page.getResources()).thenReturn(resources);
|
||||
|
||||
// Create empty list of XObject names
|
||||
List<COSName> emptyList = new ArrayList<>();
|
||||
when(resources.getXObjectNames()).thenReturn(emptyList);
|
||||
|
||||
// Execute the method
|
||||
service.removeImagesFromPdf(document);
|
||||
|
||||
// Verify that no modifications were made
|
||||
verify(resources, never()).put(any(COSName.class), any(PDXObject.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testRemoveImagesFromPdf_MultiplePages() throws IOException {
|
||||
// Mock PDF document and its components
|
||||
PDDocument document = mock(PDDocument.class);
|
||||
PDPage page1 = mock(PDPage.class);
|
||||
PDPage page2 = mock(PDPage.class);
|
||||
PDResources resources1 = mock(PDResources.class);
|
||||
PDResources resources2 = mock(PDResources.class);
|
||||
PDPageTree pageTree = mock(PDPageTree.class);
|
||||
|
||||
// Configure page tree to iterate over our two pages
|
||||
when(document.getPages()).thenReturn(pageTree);
|
||||
Iterator<PDPage> pageIterator = Arrays.asList(page1, page2).iterator();
|
||||
when(pageTree.iterator()).thenReturn(pageIterator);
|
||||
|
||||
// Set up page resources
|
||||
when(page1.getResources()).thenReturn(resources1);
|
||||
when(page2.getResources()).thenReturn(resources2);
|
||||
|
||||
// Set up image XObjects for page 1
|
||||
COSName img1 = COSName.getPDFName("Im1");
|
||||
when(resources1.getXObjectNames()).thenReturn(Collections.singletonList(img1));
|
||||
when(resources1.isImageXObject(img1)).thenReturn(true);
|
||||
|
||||
// Set up image XObjects for page 2
|
||||
COSName img2 = COSName.getPDFName("Im2");
|
||||
when(resources2.getXObjectNames()).thenReturn(Collections.singletonList(img2));
|
||||
when(resources2.isImageXObject(img2)).thenReturn(true);
|
||||
|
||||
// Execute the method
|
||||
service.removeImagesFromPdf(document);
|
||||
|
||||
// Verify that images were removed from both pages
|
||||
verify(resources1, times(1)).put(eq(img1), Mockito.<PDXObject>isNull());
|
||||
verify(resources2, times(1)).put(eq(img2), Mockito.<PDXObject>isNull());
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user