From ff5ea1c5b02a61e03b6a6a55b55d0b9a65666d02 Mon Sep 17 00:00:00 2001 From: Phil Ewels Date: Wed, 13 Aug 2025 00:27:19 +0200 Subject: [PATCH 01/27] Material design SVG icons instead of PNG --- .../FastQC/Report/HTMLReportArchive.java | 53 +++++++++++-------- 1 file changed, 31 insertions(+), 22 deletions(-) diff --git a/uk/ac/babraham/FastQC/Report/HTMLReportArchive.java b/uk/ac/babraham/FastQC/Report/HTMLReportArchive.java index 334eda5..2e93497 100644 --- a/uk/ac/babraham/FastQC/Report/HTMLReportArchive.java +++ b/uk/ac/babraham/FastQC/Report/HTMLReportArchive.java @@ -93,24 +93,29 @@ public HTMLReportArchive (SequenceFile sequenceFile, QCModule [] modules, File h // Add an icon before the module name + xhtml.writeStartElement("svg"); + xhtml.writeAttribute("xmlns", "http://www.w3.org/2000/svg"); + xhtml.writeAttribute("width", "24"); + xhtml.writeAttribute("height", "24"); + xhtml.writeAttribute("viewBox", "0 0 24 24"); + xhtml.writeStartElement("path"); if (modules[m].raisesError()) { - xhtml.writeEmptyElement("img"); - xhtml.writeAttribute("src",base64ForIcon("Icons/error.png")); - xhtml.writeAttribute("alt","[FAIL]"); + xhtml.writeAttribute("fill", "#d65d3e"); + xhtml.writeAttribute("d", "M12 2c5.53 0 10 4.47 10 10s-4.47 10-10 10S2 17.53 2 12S6.47 2 12 2m3.59 5L12 10.59L8.41 7L7 8.41L10.59 12L7 15.59L8.41 17L12 13.41L15.59 17L17 15.59L13.41 12L17 8.41z"); } - + else if (modules[m].raisesWarning()) { - xhtml.writeEmptyElement("img"); - xhtml.writeAttribute("src",base64ForIcon("Icons/warning.png")); - xhtml.writeAttribute("alt","[WARN]"); + xhtml.writeAttribute("fill", "#eab30d"); + xhtml.writeAttribute("d", "M13 14h-2V9h2m0 9h-2v-2h2M1 21h22L12 2z"); } else { - xhtml.writeEmptyElement("img"); - xhtml.writeAttribute("src",base64ForIcon("Icons/tick.png")); - xhtml.writeAttribute("alt","[OK]"); + xhtml.writeAttribute("fill", "#4ba359"); + xhtml.writeAttribute("d", "M12 2C6.5 2 2 6.5 2 12s4.5 10 10 10s10-4.5 10-10S17.5 2 12 2m-2 15l-5-5l1.41-1.41L10 14.17l7.59-7.59L19 8z"); } + xhtml.writeEndElement(); // path + xhtml.writeEndElement(); // svg xhtml.writeCharacters(modules[m].name()); @@ -248,10 +253,7 @@ private void startDocument () throws IOException,XMLStreamException // Add in the icon files for pass/fail/warn for(String icnName:new String[]{ - "fastqc_icon.png", - "warning.png", - "error.png", - "tick.png"}) + "fastqc_icon.png"}) { InputStream in =getClass().getResourceAsStream("/Templates/Icons/"+icnName); if(in==null) continue; @@ -336,22 +338,29 @@ private void startDocument () throws IOException,XMLStreamException continue; } xhtml.writeStartElement("li"); - xhtml.writeEmptyElement("img"); + xhtml.writeStartElement("svg"); + xhtml.writeAttribute("xmlns", "http://www.w3.org/2000/svg"); + xhtml.writeAttribute("width", "24"); + xhtml.writeAttribute("height", "24"); + xhtml.writeAttribute("viewBox", "0 0 24 24"); + xhtml.writeStartElement("path"); if (modules[m].raisesError()) { - xhtml.writeAttribute("src", base64ForIcon("Icons/error.png")); - xhtml.writeAttribute("alt", "[FAIL]"); + xhtml.writeAttribute("fill", "#d65d3e"); + xhtml.writeAttribute("d", "M12 2c5.53 0 10 4.47 10 10s-4.47 10-10 10S2 17.53 2 12S6.47 2 12 2m3.59 5L12 10.59L8.41 7L7 8.41L10.59 12L7 15.59L8.41 17L12 13.41L15.59 17L17 15.59L13.41 12L17 8.41z"); summaryText.append("FAIL"); } else if (modules[m].raisesWarning()) { - xhtml.writeAttribute("src", base64ForIcon("Icons/warning.png")); - xhtml.writeAttribute("alt", "[WARNING]"); + xhtml.writeAttribute("fill", "#eab30d"); + xhtml.writeAttribute("d", "M13 14h-2V9h2m0 9h-2v-2h2M1 21h22L12 2z"); summaryText.append("WARN"); } else { - xhtml.writeAttribute("src", base64ForIcon("Icons/tick.png")); - xhtml.writeAttribute("alt", "[PASS]"); + xhtml.writeAttribute("fill", "#4ba359"); + xhtml.writeAttribute("d", "M12 2C6.5 2 2 6.5 2 12s4.5 10 10 10s10-4.5 10-10S17.5 2 12 2m-2 15l-5-5l1.41-1.41L10 14.17l7.59-7.59L19 8z"); summaryText.append("PASS"); } + xhtml.writeEndElement(); // path + xhtml.writeEndElement(); // svg summaryText.append("\t"); summaryText.append(modules[m].name()); summaryText.append("\t"); @@ -409,4 +418,4 @@ private void closeDocument () throws XMLStreamException -} +} \ No newline at end of file From dd99dd52cacde39d5e12eb72040310de41a175ad Mon Sep 17 00:00:00 2001 From: Phil Ewels Date: Wed, 13 Aug 2025 01:22:04 +0200 Subject: [PATCH 02/27] Playing with refreshed sidebar style --- Templates/header_template.html | 66 +++++++++++++++---- .../FastQC/Report/HTMLReportArchive.java | 55 ++++++++-------- 2 files changed, 83 insertions(+), 38 deletions(-) diff --git a/Templates/header_template.html b/Templates/header_template.html index 7ffb43b..01451ea 100644 --- a/Templates/header_template.html +++ b/Templates/header_template.html @@ -1,10 +1,10 @@ @media screen { div.summary { - width: 18em; position:fixed; top: 3em; - margin:1em 0 0 1em; + margin-top:1em; + width: 18em; } div.main { @@ -29,7 +29,6 @@ margin:0; padding: 0.5em; font-size: 200%; - font-weight: bold; position:fixed; width:100%; top:0; @@ -85,7 +84,6 @@ margin:0; padding: 0.5em; font-size: 200%; - font-weight: bold; width:100%; } @@ -93,6 +91,7 @@ display:inline-block; float:left; clear:left; + font-weight: bold; } #header_filename { display:inline-block; @@ -102,22 +101,23 @@ margin-right:2em; text-align: right; } + #header_filename p { + margin: 0; + } div.header h3 { font-size: 50%; margin-bottom: 0; } - + + div.summary h2 { + margin-left: 1rem; + } div.summary ul { padding-left:0; list-style-type:none; } - - div.summary ul li img { - margin-bottom:-0.5em; - margin-top:0.5em; - } - + div.main { background-color: white; } @@ -184,3 +184,47 @@ padding-top: 0; margin-top: 0; } + + .summary li { + padding: 0.2rem 1rem; + border-bottom: 1px solid #CCC; + } + .summary li:last-child { + border-bottom: none; + } + .summary li a { + text-decoration: none; + color: #000; + font-size: 0.9rem; + } + .summary li span { + display: inline-block; + border: 2px solid; + border-radius: 0.2rem; + font-size: 0.7rem; + padding: 0.1rem 0.2rem; + margin-right: 0.4rem; + text-align: center; + width: 3rem; + text-transform: uppercase; + } + .sidebar-error { + background-color: #f0c6bc; + color: #862a13; + border-color: #862a13; + } + .sidebar-warning { + background-color: #e8d28f; + color: #8d6c08; + border-color: #8d6c08; + } + .sidebar-pass { + background-color: #afe0b7; + color: #2f6638; + border-color: #2f6638; + } + + h2 svg { + vertical-align: -0.1rem; + margin-right: 0.2rem; + } diff --git a/uk/ac/babraham/FastQC/Report/HTMLReportArchive.java b/uk/ac/babraham/FastQC/Report/HTMLReportArchive.java index 2e93497..e518946 100644 --- a/uk/ac/babraham/FastQC/Report/HTMLReportArchive.java +++ b/uk/ac/babraham/FastQC/Report/HTMLReportArchive.java @@ -259,9 +259,9 @@ private void startDocument () throws IOException,XMLStreamException if(in==null) continue; zip.putNextEntry(new ZipEntry(folderName()+"/Icons/"+icnName)); int len; - while ((len = in.read(buffer)) > 0) { - zip.write(buffer, 0, len); - } + while ((len = in.read(buffer)) > 0) { + zip.write(buffer, 0, len); + } in.close(); zip.closeEntry(); } @@ -299,7 +299,7 @@ private void startDocument () throws IOException,XMLStreamException xhtml.writeStartElement("body"); - xhtml.writeStartElement("div"); + xhtml.wrxiteStartElement("div"); xhtml.writeAttribute("class", "header"); xhtml.writeStartElement("div"); @@ -313,9 +313,14 @@ private void startDocument () throws IOException,XMLStreamException xhtml.writeStartElement("div"); xhtml.writeAttribute("id", "header_filename"); + xhtml.writeStartElement("p"); xhtml.writeCharacters(df.format(new Date())); - xhtml.writeEmptyElement("br"); + xhtml.writeEndElement();//p + xhtml.writeStartElement("p"); + xhtml.writeStartElement("strong"); xhtml.writeCharacters(sequenceFile.name()); + xhtml.writeEndElement();//strong + xhtml.writeEndElement();//p xhtml.writeEndElement();//div xhtml.writeEndElement();//div @@ -338,42 +343,38 @@ private void startDocument () throws IOException,XMLStreamException continue; } xhtml.writeStartElement("li"); - xhtml.writeStartElement("svg"); - xhtml.writeAttribute("xmlns", "http://www.w3.org/2000/svg"); - xhtml.writeAttribute("width", "24"); - xhtml.writeAttribute("height", "24"); - xhtml.writeAttribute("viewBox", "0 0 24 24"); - xhtml.writeStartElement("path"); + xhtml.writeStartElement("a"); + xhtml.writeAttribute("href", "#M"+m); + + xhtml.writeStartElement("span"); if (modules[m].raisesError()) { - xhtml.writeAttribute("fill", "#d65d3e"); - xhtml.writeAttribute("d", "M12 2c5.53 0 10 4.47 10 10s-4.47 10-10 10S2 17.53 2 12S6.47 2 12 2m3.59 5L12 10.59L8.41 7L7 8.41L10.59 12L7 15.59L8.41 17L12 13.41L15.59 17L17 15.59L13.41 12L17 8.41z"); + xhtml.writeAttribute("class", "sidebar-error"); + xhtml.writeCharacters("Error"); summaryText.append("FAIL"); } else if (modules[m].raisesWarning()) { - xhtml.writeAttribute("fill", "#eab30d"); - xhtml.writeAttribute("d", "M13 14h-2V9h2m0 9h-2v-2h2M1 21h22L12 2z"); + xhtml.writeAttribute("class", "sidebar-warning"); + xhtml.writeCharacters("Warn"); summaryText.append("WARN"); } else { - xhtml.writeAttribute("fill", "#4ba359"); - xhtml.writeAttribute("d", "M12 2C6.5 2 2 6.5 2 12s4.5 10 10 10s10-4.5 10-10S17.5 2 12 2m-2 15l-5-5l1.41-1.41L10 14.17l7.59-7.59L19 8z"); + xhtml.writeAttribute("class", "sidebar-pass"); + xhtml.writeCharacters("Pass"); summaryText.append("PASS"); } - xhtml.writeEndElement(); // path - xhtml.writeEndElement(); // svg + xhtml.writeEndElement(); // span + + xhtml.writeCharacters(modules[m].name()); + xhtml.writeEndElement();//a + xhtml.writeEndElement();//li + summaryText.append("\t"); summaryText.append(modules[m].name()); summaryText.append("\t"); summaryText.append(sequenceFile.name()); summaryText.append(FastQCConfig.getInstance().lineSeparator); - - xhtml.writeStartElement("a"); - xhtml.writeAttribute("href", "#M"+m); - xhtml.writeCharacters(modules[m].name()); - xhtml.writeEndElement();//a - xhtml.writeEndElement();//li - - + + } xhtml.writeEndElement();//ul xhtml.writeEndElement();//div From 8a77c3270682ba9500f38b4dbafca6354294b115 Mon Sep 17 00:00:00 2001 From: Phil Ewels Date: Sat, 23 Aug 2025 23:40:47 +0200 Subject: [PATCH 03/27] Rename header template to .CSS, create new scaffold HTML template --- .../{header_template.html => fastqc.css} | 2 +- Templates/report_template.html | 35 ++ .../FastQC/Report/HTMLReportArchive.java | 302 ++++++++---------- 3 files changed, 173 insertions(+), 166 deletions(-) rename Templates/{header_template.html => fastqc.css} (99%) create mode 100644 Templates/report_template.html diff --git a/Templates/header_template.html b/Templates/fastqc.css similarity index 99% rename from Templates/header_template.html rename to Templates/fastqc.css index 01451ea..f52cd07 100644 --- a/Templates/header_template.html +++ b/Templates/fastqc.css @@ -1,5 +1,5 @@ - @media screen { +@media screen { div.summary { position:fixed; top: 3em; diff --git a/Templates/report_template.html b/Templates/report_template.html new file mode 100644 index 0000000..90be960 --- /dev/null +++ b/Templates/report_template.html @@ -0,0 +1,35 @@ + + + + {{TITLE}} + + + +
+
+ FastQCFastQC Report +
+
+

{{DATE}}

+

{{FILENAME}}

+
+
+ +
+

Summary

+
    +{{SUMMARY_ITEMS}} +
+
+ +
+{{MODULE_CONTENT}} +
+ + + + diff --git a/uk/ac/babraham/FastQC/Report/HTMLReportArchive.java b/uk/ac/babraham/FastQC/Report/HTMLReportArchive.java index e518946..32e7e20 100644 --- a/uk/ac/babraham/FastQC/Report/HTMLReportArchive.java +++ b/uk/ac/babraham/FastQC/Report/HTMLReportArchive.java @@ -66,32 +66,47 @@ public class HTMLReportArchive { private byte [] buffer = new byte[1024]; private File htmlFile; private File zipFile; + private StringWriter moduleContentWriter; + private String htmlTemplate; public HTMLReportArchive (SequenceFile sequenceFile, QCModule [] modules, File htmlFile) throws IOException, XMLStreamException { this.sequenceFile = sequenceFile; this.modules = modules; this.htmlFile = htmlFile; this.zipFile = new File(htmlFile.getAbsoluteFile().toString().replaceAll("\\.html$", "")+".zip"); - StringWriter htmlStr = new StringWriter(); + + // Load the HTML template + this.htmlTemplate = loadTemplate("/Templates/report_template.html"); + + // Create XMLStreamWriter for module content + this.moduleContentWriter = new StringWriter(); XMLOutputFactory xmlfactory = XMLOutputFactory.newInstance(); - this.xhtml= xmlfactory.createXMLStreamWriter(htmlStr); - - + this.xhtml= xmlfactory.createXMLStreamWriter(moduleContentWriter); + + zip = new ZipOutputStream(new FileOutputStream(zipFile)); zip.putNextEntry(new ZipEntry(folderName()+"/")); zip.putNextEntry(new ZipEntry(folderName()+"/Icons/")); zip.putNextEntry(new ZipEntry(folderName()+"/Images/")); - startDocument(); + + // Initialize data document + data.append("##FastQC\t"); + data.append(FastQCApplication.VERSION); + data.append("\n"); + + // Add icon files to zip + addIconsToZip(); + + // Generate module content for (int m=0;m>"); data.append(modules[m].name()); @@ -135,26 +149,36 @@ else if (modules[m].raisesWarning()) { xhtml.writeEndElement(); modules[m].makeReport(this); data.append(">>END_MODULE\n"); - + xhtml.writeEndElement(); } - closeDocument(); - - zip.putNextEntry(new ZipEntry(folderName()+"/fastqc_report.html")); + + // Close XMLStreamWriter and generate final HTML xhtml.flush(); xhtml.close(); - zip.write(htmlStr.toString().getBytes()); + + // Generate final HTML from template + String finalHtml = generateHtmlFromTemplate(); + + zip.putNextEntry(new ZipEntry(folderName()+"/fastqc_report.html")); + zip.write(finalHtml.getBytes()); zip.closeEntry(); zip.putNextEntry(new ZipEntry(folderName()+"/fastqc_data.txt")); zip.write(data.toString().getBytes()); zip.closeEntry(); - + + // Generate summary.txt + String summaryText = generateSummaryText(); + zip.putNextEntry(new ZipEntry(folderName()+"/summary.txt")); + zip.write(summaryText.getBytes()); + zip.closeEntry(); + //XSL-FO try { DocumentBuilderFactory domFactory=DocumentBuilderFactory.newInstance(); domFactory.setNamespaceAware(false); DocumentBuilder builder=domFactory.newDocumentBuilder(); - Document src=builder.parse(new InputSource( new StringReader(htmlStr.toString()))); + Document src=builder.parse(new InputSource( new StringReader(finalHtml))); InputStream rsrc=getClass().getResourceAsStream("/Templates/fastqc2fo.xsl"); if(rsrc!=null) { @@ -162,7 +186,7 @@ else if (modules[m].raisesWarning()) { builder=domFactory.newDocumentBuilder(); Document html2fo=builder.parse(rsrc); rsrc.close(); - + TransformerFactory tf=TransformerFactory.newInstance(); Templates templates=tf.newTemplates(new DOMSource(html2fo)); zip.putNextEntry(new ZipEntry(folderName()+"/fastqc.fo")); @@ -173,19 +197,19 @@ else if (modules[m].raisesWarning()) { catch (Exception e) { e.printStackTrace(); } - - + + zip.close(); - + // Save the HTML file at the same level as the zip file - + PrintWriter pr = new PrintWriter(new FileWriter(htmlFile)); - - pr.print(htmlStr.toString()); - + + pr.print(finalHtml); + pr.close(); - + if (FastQCConfig.getInstance().do_unzip) { unzipZipFile(zipFile); if (FastQCConfig.getInstance().delete_after_unzip) { @@ -193,18 +217,18 @@ else if (modules[m].raisesWarning()) { } } } - + private void unzipZipFile (File file) throws IOException { ZipFile zipFile = new ZipFile(file); Enumeration entries = zipFile.entries(); int size; byte [] buffer = new byte[1024]; - + while (entries.hasMoreElements()) { ZipEntry entry = entries.nextElement(); - + // System.out.println("Going to extract '"+entry.getName()+"'"); - + if (entry.isDirectory()) { File dir = new File(file.getParent()+"/"+entry.getName()); if (dir.exists() && dir.isDirectory()) continue; // Don't need to do anything @@ -222,7 +246,7 @@ private void unzipZipFile (File file) throws IOException { bos.close(); bis.close(); } - + zipFile.close(); } @@ -230,27 +254,20 @@ public XMLStreamWriter xhtmlStream () { return this.xhtml; } - + public StringBuffer dataDocument() { return data; } - + public String folderName () { return htmlFile.getName().replaceAll("\\.html$", ""); } - + public ZipOutputStream zipFile () { return zip; } - - private void startDocument () throws IOException,XMLStreamException - { - - // Just put the fastQC version at the start of the text report - data.append("##FastQC\t"); - data.append(FastQCApplication.VERSION); - data.append("\n"); - + + private void addIconsToZip() throws IOException { // Add in the icon files for pass/fail/warn for(String icnName:new String[]{ "fastqc_icon.png"}) @@ -265,129 +282,99 @@ private void startDocument () throws IOException,XMLStreamException in.close(); zip.closeEntry(); } - - + } - SimpleDateFormat df = new SimpleDateFormat("EEE d MMM yyyy"); - - xhtml.writeDTD(""); - xhtml.writeStartElement("html"); - xhtml.writeStartElement("head"); - - xhtml.writeStartElement("title"); - xhtml.writeCharacters(sequenceFile.name()); - xhtml.writeCharacters(" FastQC Report"); - xhtml.writeEndElement();//title - - InputStream rsrc=getClass().getResourceAsStream("/Templates/header_template.html"); - if(rsrc!=null) - { - xhtml.writeStartElement("style"); - xhtml.writeAttribute("type", "text/css"); - - byte array[]=new byte[128]; - int nRead; - while((nRead=rsrc.read(array))!=-1) { xhtml.writeCharacters(new String(array,0,nRead));} - rsrc.close(); - xhtml.writeEndElement();//style - } - - - - - xhtml.writeEndElement();//head - - xhtml.writeStartElement("body"); - - xhtml.wrxiteStartElement("div"); - xhtml.writeAttribute("class", "header"); - - xhtml.writeStartElement("div"); - xhtml.writeAttribute("id", "header_title"); - - xhtml.writeEmptyElement("img"); - xhtml.writeAttribute("src", base64ForIcon("Icons/fastqc_icon.png")); - xhtml.writeAttribute("alt", "FastQC"); - xhtml.writeCharacters("FastQC Report"); - xhtml.writeEndElement();//div - - xhtml.writeStartElement("div"); - xhtml.writeAttribute("id", "header_filename"); - xhtml.writeStartElement("p"); - xhtml.writeCharacters(df.format(new Date())); - xhtml.writeEndElement();//p - xhtml.writeStartElement("p"); - xhtml.writeStartElement("strong"); - xhtml.writeCharacters(sequenceFile.name()); - xhtml.writeEndElement();//strong - xhtml.writeEndElement();//p - xhtml.writeEndElement();//div - xhtml.writeEndElement();//div - - - xhtml.writeStartElement("div"); - xhtml.writeAttribute("class", "summary"); - - xhtml.writeStartElement("h2"); - xhtml.writeCharacters("Summary"); - xhtml.writeEndElement();//h2 - - - xhtml.writeStartElement("ul"); - + private String loadTemplate(String templatePath) throws IOException { + InputStream templateStream = getClass().getResourceAsStream(templatePath); + if (templateStream == null) { + throw new IOException("Template not found: " + templatePath); + } + + StringWriter templateWriter = new StringWriter(); + byte[] buffer = new byte[1024]; + int nRead; + while ((nRead = templateStream.read(buffer)) != -1) { + templateWriter.write(new String(buffer, 0, nRead)); + } + templateStream.close(); + return templateWriter.toString(); + } + + private String loadCss() throws IOException { + return loadTemplate("/Templates/fastqc.css"); + } + + private String generateSummaryItems() { + StringBuffer summaryItems = new StringBuffer(); + + for (int m=0;m\n"); + summaryItems.append(" \n"); + summaryItems.append(" Error"); + } else if (modules[m].raisesWarning()) { + summaryItems.append("sidebar-warning\">Warn"); + } else { + summaryItems.append("sidebar-pass\">Pass"); + } + + summaryItems.append(""); + summaryItems.append(modules[m].name()); + summaryItems.append("\n \n"); + summaryItems.append(" \n"); + } + + return summaryItems.toString(); + } + + private String generateSummaryText() { StringBuffer summaryText = new StringBuffer(); - + for (int m=0;m Date: Sat, 23 Aug 2025 23:53:29 +0200 Subject: [PATCH 04/27] Move more HTML out of the .java file and into file fragments --- Templates/Icons/error.svg | 3 + Templates/Icons/pass.svg | 3 + Templates/Icons/warning.svg | 3 + Templates/module_wrapper.html | 6 + Templates/report_template.html | 2 +- Templates/sidebar_item.html | 5 + .../FastQC/Report/HTMLReportArchive.java | 154 ++++++++++-------- 7 files changed, 104 insertions(+), 72 deletions(-) create mode 100644 Templates/Icons/error.svg create mode 100644 Templates/Icons/pass.svg create mode 100644 Templates/Icons/warning.svg create mode 100644 Templates/module_wrapper.html create mode 100644 Templates/sidebar_item.html diff --git a/Templates/Icons/error.svg b/Templates/Icons/error.svg new file mode 100644 index 0000000..e0adc44 --- /dev/null +++ b/Templates/Icons/error.svg @@ -0,0 +1,3 @@ + + + diff --git a/Templates/Icons/pass.svg b/Templates/Icons/pass.svg new file mode 100644 index 0000000..39f109f --- /dev/null +++ b/Templates/Icons/pass.svg @@ -0,0 +1,3 @@ + + + diff --git a/Templates/Icons/warning.svg b/Templates/Icons/warning.svg new file mode 100644 index 0000000..3023ec0 --- /dev/null +++ b/Templates/Icons/warning.svg @@ -0,0 +1,3 @@ + + + diff --git a/Templates/module_wrapper.html b/Templates/module_wrapper.html new file mode 100644 index 0000000..26dda66 --- /dev/null +++ b/Templates/module_wrapper.html @@ -0,0 +1,6 @@ +
+

+ {{STATUS_ICON}}{{MODULE_NAME}} +

+{{MODULE_CONTENT}} +
diff --git a/Templates/report_template.html b/Templates/report_template.html index 90be960..4b58f94 100644 --- a/Templates/report_template.html +++ b/Templates/report_template.html @@ -9,7 +9,7 @@
- FastQCFastQC Report + FastQCFastQC Report

{{DATE}}

diff --git a/Templates/sidebar_item.html b/Templates/sidebar_item.html new file mode 100644 index 0000000..0f7b354 --- /dev/null +++ b/Templates/sidebar_item.html @@ -0,0 +1,5 @@ +
  • + + {{STATUS_TEXT}}{{MODULE_NAME}} + +
  • diff --git a/uk/ac/babraham/FastQC/Report/HTMLReportArchive.java b/uk/ac/babraham/FastQC/Report/HTMLReportArchive.java index 32e7e20..0328dac 100644 --- a/uk/ac/babraham/FastQC/Report/HTMLReportArchive.java +++ b/uk/ac/babraham/FastQC/Report/HTMLReportArchive.java @@ -97,68 +97,15 @@ public HTMLReportArchive (SequenceFile sequenceFile, QCModule [] modules, File h // Add icon files to zip addIconsToZip(); - // Generate module content - for (int m=0;m>"); - data.append(modules[m].name()); - data.append("\t"); - if (modules[m].raisesError()) { - data.append("fail"); - } - else if (modules[m].raisesWarning()) { - data.append("warn"); - } - else { - data.append("pass"); - } - data.append("\n"); - xhtml.writeEndElement(); - modules[m].makeReport(this); - data.append(">>END_MODULE\n"); - - xhtml.writeEndElement(); - } - - // Close XMLStreamWriter and generate final HTML + // Close XMLStreamWriter (no longer needed for main content) xhtml.flush(); xhtml.close(); // Generate final HTML from template - String finalHtml = generateHtmlFromTemplate(); + String finalHtml = generateHtmlFromTemplate(moduleContent); zip.putNextEntry(new ZipEntry(folderName()+"/fastqc_report.html")); zip.write(finalHtml.getBytes()); @@ -300,34 +247,35 @@ private String loadTemplate(String templatePath) throws IOException { return templateWriter.toString(); } - private String loadCss() throws IOException { + private String loadCss() throws IOException { return loadTemplate("/Templates/fastqc.css"); } - private String generateSummaryItems() { + private String generateSummaryItems() throws IOException { StringBuffer summaryItems = new StringBuffer(); + String sidebarItemTemplate = loadTemplate("/Templates/sidebar_item.html"); for (int m=0;m\n"); - summaryItems.append(" \n"); - summaryItems.append(" Error"); + item = item.replace("{{STATUS_CLASS}}", "sidebar-error"); + item = item.replace("{{STATUS_TEXT}}", "Error"); } else if (modules[m].raisesWarning()) { - summaryItems.append("sidebar-warning\">Warn"); + item = item.replace("{{STATUS_CLASS}}", "sidebar-warning"); + item = item.replace("{{STATUS_TEXT}}", "Warn"); } else { - summaryItems.append("sidebar-pass\">Pass"); + item = item.replace("{{STATUS_CLASS}}", "sidebar-pass"); + item = item.replace("{{STATUS_TEXT}}", "Pass"); } - summaryItems.append(""); - summaryItems.append(modules[m].name()); - summaryItems.append("\n \n"); - summaryItems.append(" \n"); + summaryItems.append(item).append("\n"); } return summaryItems.toString(); @@ -359,7 +307,71 @@ private String generateSummaryText() { return summaryText.toString(); } - private String generateHtmlFromTemplate() throws IOException { + private String getStatusIcon(QCModule module) throws IOException { + if (module.raisesError()) { + return loadTemplate("/Templates/Icons/error.svg"); + } else if (module.raisesWarning()) { + return loadTemplate("/Templates/Icons/warning.svg"); + } else { + return loadTemplate("/Templates/Icons/pass.svg"); + } + } + + private String generateModuleContent() throws IOException, XMLStreamException { + StringBuffer allModulesContent = new StringBuffer(); + String moduleWrapperTemplate = loadTemplate("/Templates/module_wrapper.html"); + + // Generate content for each module + for (int m=0;m>"); + data.append(modules[m].name()); + data.append("\t"); + if (modules[m].raisesError()) { + data.append("fail"); + } else if (modules[m].raisesWarning()) { + data.append("warn"); + } else { + data.append("pass"); + } + data.append("\n"); + + // Let the module generate its content + modules[m].makeReport(this); + data.append(">>END_MODULE\n"); + + // Close the module's XMLStreamWriter + moduleXhtml.flush(); + moduleXhtml.close(); + + // Restore the original XMLStreamWriter + this.xhtml = originalXhtml; + + // Apply the module wrapper template + String moduleWrapper = moduleWrapperTemplate; + moduleWrapper = moduleWrapper.replace("{{MODULE_INDEX}}", String.valueOf(m)); + moduleWrapper = moduleWrapper.replace("{{MODULE_NAME}}", modules[m].name()); + moduleWrapper = moduleWrapper.replace("{{STATUS_ICON}}", getStatusIcon(modules[m])); + moduleWrapper = moduleWrapper.replace("{{MODULE_CONTENT}}", moduleBodyWriter.toString()); + + allModulesContent.append(moduleWrapper).append("\n"); + } + + return allModulesContent.toString(); + } + + private String generateHtmlFromTemplate(String moduleContent) throws IOException { SimpleDateFormat df = new SimpleDateFormat("EEE d MMM yyyy"); String html = htmlTemplate; @@ -369,7 +381,7 @@ private String generateHtmlFromTemplate() throws IOException { html = html.replace("{{FILENAME}}", sequenceFile.name()); html = html.replace("{{FASTQC_ICON_BASE64}}", base64ForIcon("Icons/fastqc_icon.png")); html = html.replace("{{SUMMARY_ITEMS}}", generateSummaryItems()); - html = html.replace("{{MODULE_CONTENT}}", moduleContentWriter.toString()); + html = html.replace("{{MODULE_CONTENT}}", moduleContent); html = html.replace("{{VERSION}}", FastQCApplication.VERSION); return html; From 897ecc74e8a0edf52cd96e582ced874df202b5e9 Mon Sep 17 00:00:00 2001 From: Phil Ewels Date: Sun, 24 Aug 2025 00:01:01 +0200 Subject: [PATCH 05/27] Clean up CSS file, remove @screen stuff and remove duplicates --- Templates/fastqc.css | 310 ++++++++++++++++++++----------------------- 1 file changed, 146 insertions(+), 164 deletions(-) diff --git a/Templates/fastqc.css b/Templates/fastqc.css index f52cd07..859d729 100644 --- a/Templates/fastqc.css +++ b/Templates/fastqc.css @@ -1,62 +1,4 @@ - -@media screen { - div.summary { - position:fixed; - top: 3em; - margin-top:1em; - width: 18em; - } - - div.main { - display:block; - position:absolute; - overflow:auto; - height:auto; - width:auto; - top:4.5em; - bottom:2.3em; - left:18em; - right:0; - border-left: 1px solid #CCC; - padding:0 0 0 1em; - background-color: white; - z-index:1; - } - - div.header { - background-color: #EEE; - border:0; - margin:0; - padding: 0.5em; - font-size: 200%; - position:fixed; - width:100%; - top:0; - left:0; - z-index:2; - } - - div.footer { - background-color: #EEE; - border:0; - margin:0; - padding:0.5em; - height: 1.3em; - overflow:hidden; - font-size: 100%; - font-weight: bold; - position:fixed; - bottom:0; - width:100%; - z-index:2; - } - - img.indented { - margin-left: 3em; - } - } - - @media print { +@media print { img { max-width:100% !important; page-break-inside: avoid; @@ -67,164 +9,204 @@ div.header { background-color: #FFF; } - - } - - body { - font-family: sans-serif; - color: #000; + +} + +body { + font-family: sans-serif; + color: #000; background-color: #FFF; border: 0; margin: 0; padding: 0; - } - - div.header { +} + +div.summary { + position:fixed; + top: 3em; + margin-top:1em; + width: 18em; +} + +div.summary h2 { + margin-left: 1rem; +} + +div.summary ul { + padding-left:0; + list-style-type:none; +} + +div.main { + display:block; + position:absolute; + overflow:auto; + height:auto; + width:auto; + top:4.5em; + bottom:2.3em; + left:18em; + right:0; + border-left: 1px solid #CCC; + padding:0 0 0 1em; + background-color: white; + z-index:1; +} + +div.module { + padding-bottom:1.5em; + padding-top:1.5em; +} + +div.header { + background-color: #EEE; border:0; margin:0; padding: 0.5em; font-size: 200%; + position:fixed; width:100%; - } - - #header_title { + top:0; + left:0; + z-index:2; +} + +#header_title { display:inline-block; float:left; clear:left; font-weight: bold; - } - #header_filename { +} + +#header_filename { display:inline-block; float:right; clear:right; font-size: 50%; margin-right:2em; text-align: right; - } - #header_filename p { - margin: 0; - } +} - div.header h3 { +#header_filename p { + margin: 0; +} + +div.header h3 { font-size: 50%; margin-bottom: 0; - } +} - div.summary h2 { - margin-left: 1rem; - } - div.summary ul { - padding-left:0; - list-style-type:none; - } - - div.main { - background-color: white; - } - - div.module { - padding-bottom:1.5em; - padding-top:1.5em; - } - - div.footer { +div.footer { background-color: #EEE; border:0; margin:0; - padding: 0.5em; + padding:0.5em; + height: 1.3em; + overflow:hidden; font-size: 100%; font-weight: bold; + position:fixed; + bottom:0; width:100%; - } + z-index:2; +} +img.indented { + margin-left: 3em; +} - a { +a { color: #000080; - } +} - a:hover { +a:hover { color: #800000; - } - - h2 { +} + +h2 { color: #800000; padding-bottom: 0; margin-bottom: 0; clear:left; - } +} - table { +table { margin-left: 3em; text-align: center; - } - - th { +} + +th { text-align: center; background-color: #000080; color: #FFF; padding: 0.4em; - } - - td { - font-family: monospace; +} + +td { + font-family: monospace; text-align: left; background-color: #EEE; color: #000; padding: 0.4em; - } +} - img { +img { padding-top: 0; margin-top: 0; border-top: 0; - } +} - - p { +p { padding-top: 0; margin-top: 0; - } - - .summary li { - padding: 0.2rem 1rem; - border-bottom: 1px solid #CCC; - } - .summary li:last-child { - border-bottom: none; - } - .summary li a { - text-decoration: none; - color: #000; - font-size: 0.9rem; - } - .summary li span { - display: inline-block; - border: 2px solid; - border-radius: 0.2rem; - font-size: 0.7rem; - padding: 0.1rem 0.2rem; - margin-right: 0.4rem; - text-align: center; - width: 3rem; - text-transform: uppercase; - } - .sidebar-error { - background-color: #f0c6bc; - color: #862a13; - border-color: #862a13; - } - .sidebar-warning { - background-color: #e8d28f; - color: #8d6c08; - border-color: #8d6c08; - } - .sidebar-pass { - background-color: #afe0b7; - color: #2f6638; - border-color: #2f6638; - } - - h2 svg { - vertical-align: -0.1rem; - margin-right: 0.2rem; - } +} + +.summary li { + padding: 0.2rem 1rem; + border-bottom: 1px solid #CCC; +} + +.summary li:last-child { + border-bottom: none; +} + +.summary li a { + text-decoration: none; + color: #000; + font-size: 0.9rem; +} + +.summary li span { + display: inline-block; + border: 2px solid; + border-radius: 0.2rem; + font-size: 0.7rem; + padding: 0.1rem 0.2rem; + margin-right: 0.4rem; + text-align: center; + width: 3rem; + text-transform: uppercase; +} + +.sidebar-error { + background-color: #f0c6bc; + color: #862a13; + border-color: #862a13; +} + +.sidebar-warning { + background-color: #e8d28f; + color: #8d6c08; + border-color: #8d6c08; +} + +.sidebar-pass { + background-color: #afe0b7; + color: #2f6638; + border-color: #2f6638; +} + +h2 svg { + vertical-align: -0.1rem; + margin-right: 0.2rem; +} From d58129337aa168e97ca5deca25b2dd70551779b6 Mon Sep 17 00:00:00 2001 From: Phil Ewels Date: Sun, 24 Aug 2025 00:38:57 +0200 Subject: [PATCH 06/27] Restructure report * No fixed navbar + sidebar * Updated sidebar with nav and details * Mobile responsive design, using CSS-only approach --- Templates/fastqc.css | 489 +++++++++++++++++++++++++-------- Templates/report_template.html | 56 ++-- 2 files changed, 408 insertions(+), 137 deletions(-) diff --git a/Templates/fastqc.css b/Templates/fastqc.css index 859d729..761ade1 100644 --- a/Templates/fastqc.css +++ b/Templates/fastqc.css @@ -1,15 +1,30 @@ @media print { - img { - max-width:100% !important; - page-break-inside: avoid; - } - h2, h3 { - page-break-after: avoid; - } - div.header { - background-color: #FFF; - } + img { + max-width:100% !important; + page-break-inside: avoid; + } + h2, h3 { + page-break-after: avoid; + } + .sidebar-header { + background-color: #FFF; + } + .mobile-nav { + display: none !important; + } + .sidebar { + position: static !important; + transform: none !important; + width: auto !important; + } + .container { + flex-direction: column !important; + } +} +/* Reset and base styles */ +* { + box-sizing: border-box; } body { @@ -19,173 +34,188 @@ body { border: 0; margin: 0; padding: 0; + line-height: 1.4; } -div.summary { - position:fixed; - top: 3em; - margin-top:1em; - width: 18em; +/* Mobile navigation bar */ +.mobile-nav { + display: none; + background-color: #EEE; + padding: 0.75rem 1rem; + border-bottom: 1px solid #CCC; + position: fixed; + top: 0; + left: 0; + right: 0; + z-index: 1000; + align-items: center; + justify-content: space-between; } -div.summary h2 { - margin-left: 1rem; +.menu-toggle-input { + display: none; } -div.summary ul { - padding-left:0; - list-style-type:none; +.menu-toggle { + cursor: pointer; + padding: 0.25rem; + display: flex; + flex-direction: column; + gap: 3px; + background: none; + border: none; } -div.main { - display:block; - position:absolute; - overflow:auto; - height:auto; - width:auto; - top:4.5em; - bottom:2.3em; - left:18em; - right:0; - border-left: 1px solid #CCC; - padding:0 0 0 1em; - background-color: white; - z-index:1; +.hamburger { + width: 20px; + height: 2px; + background-color: #333; + transition: all 0.3s ease; } -div.module { - padding-bottom:1.5em; - padding-top:1.5em; +.mobile-title { + font-size: 1rem; + display: flex; + align-items: center; + justify-content: flex-end; + gap: 0.25rem; + flex: 1; + min-width: 0; /* Allow shrinking */ + margin-right: 1rem; + text-align: right; } -div.header { - background-color: #EEE; - border:0; - margin:0; - padding: 0.5em; - font-size: 200%; - position:fixed; - width:100%; - top:0; - left:0; - z-index:2; -} - -#header_title { - display:inline-block; - float:left; - clear:left; +.mobile-title-app { font-weight: bold; + flex-shrink: 0; /* Don't shrink the "FastQC:" part */ } -#header_filename { - display:inline-block; - float:right; - clear:right; - font-size: 50%; - margin-right:2em; - text-align: right; +.mobile-title-filename { + font-weight: normal; + font-size: 0.9rem; + color: #666; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + min-width: 0; /* Allow shrinking */ } -#header_filename p { - margin: 0; +.mobile-icon { + height: 20px; + width: 20px; + flex-shrink: 0; + margin: 0 !important; } -div.header h3 { - font-size: 50%; - margin-bottom: 0; +/* Main container */ +.container { + display: flex; + min-height: 100vh; } -div.footer { - background-color: #EEE; - border:0; - margin:0; - padding:0.5em; - height: 1.3em; - overflow:hidden; - font-size: 100%; - font-weight: bold; - position:fixed; - bottom:0; - width:100%; - z-index:2; +/* Sidebar */ +.sidebar { + width: 300px; + background-color: #F8F8F8; + border-right: 1px solid #CCC; + display: flex; + flex-direction: column; + position: fixed; + top: 0; + left: 0; + bottom: 0; + overflow-y: auto; } -img.indented { - margin-left: 3em; +.sidebar-header { + background-color: #EEE; + padding: 1rem; + border-bottom: 1px solid #CCC; } - -a { - color: #000080; +.sidebar-header a { + text-decoration: none; + color: #000; } -a:hover { - color: #800000; +.header-title { + font-weight: bold; + font-size: 1.25rem; + margin-bottom: 0.5rem; + display: flex; + align-items: center; + gap: 0.5rem; } -h2 { - color: #800000; - padding-bottom: 0; - margin-bottom: 0; - clear:left; +.header-title img { + height: 24px; + width: auto; + margin: 0; } -table { - margin-left: 3em; - text-align: center; +.header-filename { + font-size: 0.85rem; + color: #666; } -th { - text-align: center; - background-color: #000080; - color: #FFF; - padding: 0.4em; +.header-filename p { + margin: 0.25rem 0; } -td { - font-family: monospace; - text-align: left; - background-color: #EEE; +.header-filename strong { color: #000; - padding: 0.4em; } -img { - padding-top: 0; - margin-top: 0; - border-top: 0; +/* Navigation */ +.navigation { + flex: 1; + padding: 1rem 0; } -p { - padding-top: 0; - margin-top: 0; +.navigation h2 { + margin: 0 0 1rem 1rem; + color: #800000; + font-size: 1.1rem; } -.summary li { - padding: 0.2rem 1rem; - border-bottom: 1px solid #CCC; +.navigation ul { + padding: 0; + margin: 0; + list-style-type: none; +} + +.navigation li { + padding: 0.5rem 1rem; + border-bottom: 1px solid #DDD; + transition: background-color 0.2s ease; } -.summary li:last-child { +.navigation li:last-child { border-bottom: none; } -.summary li a { +.navigation li:hover { + background-color: #F0F0F0; +} + +.navigation li a { text-decoration: none; color: #000; font-size: 0.9rem; + display: flex; + align-items: center; + gap: 0.5rem; } -.summary li span { +.navigation li span { display: inline-block; border: 2px solid; border-radius: 0.2rem; font-size: 0.7rem; - padding: 0.1rem 0.2rem; - margin-right: 0.4rem; + padding: 0.1rem 0.3rem; text-align: center; - width: 3rem; + min-width: 3.5rem; text-transform: uppercase; + font-weight: bold; } .sidebar-error { @@ -206,7 +236,224 @@ p { border-color: #2f6638; } +/* Main content area */ +.main { + flex: 1; + margin-left: 300px; + padding: 2rem; + background-color: white; + min-height: 100vh; +} + +.module { + padding-bottom: 2rem; + padding-top: 1rem; + overflow-x: auto; +} + +/* Footer */ +.footer { + margin-top: 3rem; + padding: 1.5rem 0; + border-top: 1px solid #EEE; + font-size: 0.9rem; + color: #666; + text-align: center; +} + +/* Content styling */ +h2 { + color: #800000; + padding-bottom: 0.5rem; + margin-bottom: 1rem; + border-bottom: 2px solid #800000; + display: flex; + align-items: center; + gap: 0.5rem; +} + h2 svg { vertical-align: -0.1rem; - margin-right: 0.2rem; +} + +/* Table wrapper for horizontal scrolling */ + +table { + margin: 1rem 0; + border-collapse: collapse; + width: 100%; + max-width: 100%; + min-width: 600px; /* Ensure tables don't get too cramped */ +} + +th { + text-align: center; + background-color: #000080; + color: #FFF; + padding: 0.75rem 0.5rem; + font-weight: bold; +} + +td { + font-family: monospace; + text-align: left; + background-color: #F5F5F5; + color: #000; + padding: 0.5rem; + border-bottom: 1px solid #DDD; +} + +tr:nth-child(even) td { + background-color: #EEE; +} + +img { + max-width: 100%; + height: auto; + padding-top: 0; + margin-top: 0; + border-top: 0; + display: block; + margin-left: auto; + margin-right: auto; +} + +img.indented { + margin-left: 2rem; +} + +p { + padding-top: 0; + margin: 1rem 0; +} + +a { + color: #000080; + transition: color 0.2s ease; +} + +a:hover { + color: #800000; +} + +/* Mobile responsive styles */ +@media (max-width: 768px) { + .mobile-nav { + display: flex; + } + + .container { + padding-top: 60px; /* Account for fixed mobile nav */ + } + + .sidebar { + position: fixed; + top: 48px; + left: 0; + bottom: 0; + right: 0; + width: 100%; + height: calc(100% - 48px); + transform: translateX(-100%); + transition: transform 0.3s ease; + z-index: 999; + box-shadow: none; + } + + /* CSS-only toggle for mobile sidebar */ + .menu-toggle-input:checked ~ .container .sidebar { + transform: translateX(0); + } + + /* Hide entire sidebar header on mobile */ + .sidebar-header { + display: none; + } + + /* Hamburger animation when menu is open */ + .menu-toggle-input:checked ~ .mobile-nav .hamburger:nth-child(1) { + transform: rotate(45deg) translate(3px, 3px); + } + + .menu-toggle-input:checked ~ .mobile-nav .hamburger:nth-child(2) { + opacity: 0; + } + + .menu-toggle-input:checked ~ .mobile-nav .hamburger:nth-child(3) { + transform: rotate(-45deg) translate(4px, -4px); + } + + .main { + width: 100%; + margin-left: 0; + padding: 1rem; + overflow-x: hidden; /* Prevent main content horizontal scroll */ + } + + .module { + padding-bottom: 1.5rem; + padding-left: 0; + padding-right: 0; + } + + table { + font-size: 0.85rem; + min-width: 500px; /* Smaller minimum width for mobile */ + } + + th, td { + padding: 0.5rem 0.25rem; + } + + /* Ensure images don't cause horizontal scroll */ + img { + max-width: 100% !important; + height: auto !important; + } + + /* Remove left margin from indented images on mobile */ + img.indented { + margin-left: 0 !important; + margin-right: 0 !important; + } +} + +@media (max-width: 480px) { + .main { + padding: 0.75rem; + padding-left: 0.5rem; + padding-right: 0.5rem; + } + + .sidebar { + width: 100%; + } + + .sidebar-header { + padding: 0.75rem; + } + + .header-title { + font-size: 1.1rem; + } + + table { + font-size: 0.8rem; + min-width: 400px; /* Even smaller for very small screens */ + } + + .navigation li { + padding: 0.4rem 0.75rem; + } + + .module { + padding-left: 0; + padding-right: 0; + } + + /* Remove left margin from indented images on small mobile */ + img.indented { + margin-left: 0 !important; + margin-right: 0 !important; + } } diff --git a/Templates/report_template.html b/Templates/report_template.html index 4b58f94..6ae00c1 100644 --- a/Templates/report_template.html +++ b/Templates/report_template.html @@ -2,34 +2,58 @@ {{TITLE}} + -
    -
    - FastQCFastQC Report -
    -
    -

    {{DATE}}

    -

    {{FILENAME}}

    + + + + +
    + +
    + FastQC + FastQC: + {{FILENAME}}
    -
    -

    Summary

    - + + -
    + +
    {{MODULE_CONTENT}} -
    - From df973cf0777f4bba81ab9b4f9afbdeae7c4aa0de Mon Sep 17 00:00:00 2001 From: Phil Ewels Date: Sun, 24 Aug 2025 21:19:21 +0200 Subject: [PATCH 07/27] Basic stats - look like a definition list (CSS only) --- Templates/fastqc.css | 55 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/Templates/fastqc.css b/Templates/fastqc.css index 761ade1..758cb0b 100644 --- a/Templates/fastqc.css +++ b/Templates/fastqc.css @@ -307,6 +307,61 @@ tr:nth-child(even) td { background-color: #EEE; } +/* Style Basic Statistics table (first module) to look like a definition list */ +.module:first-of-type table { + border-collapse: separate; + border-spacing: 0; + min-width: auto; + margin: 1rem 0; + width: auto; + max-width: 600px; +} + +.module:first-of-type table thead { + display: none; /* Hide the table headers */ +} + +.module:first-of-type table tbody tr { + display: block; + margin-bottom: 1.5rem; + border: none; + background: none; +} + +.module:first-of-type table tbody td:first-child { + /* Style like definition list title (label above) */ + display: block; + font-weight: normal; + font-family: sans-serif; + background-color: transparent; + padding: 0; + border: none; + color: #666; + text-transform: uppercase; + font-size: 0.75rem; + letter-spacing: 0.8px; + margin-bottom: 0.25rem; + line-height: 1.2; +} + +.module:first-of-type table tbody td:last-child { + /* Style like definition list value (below label) */ + display: block; + font-family: sans-serif; + font-weight: normal; + background-color: transparent; + padding: 0; + margin: 0; + border: none; + color: #000; + font-size: 1.1rem; + line-height: 1.3; +} + +.module:first-of-type table tbody tr:nth-child(even) td { + background-color: transparent; +} + img { max-width: 100%; height: auto; From cebd4d4a81534f156d9b7cee2b58091c92c67b42 Mon Sep 17 00:00:00 2001 From: Phil Ewels Date: Mon, 25 Aug 2025 07:36:14 +0200 Subject: [PATCH 08/27] Basic stats: revert to table, but keep clean styling --- Templates/fastqc.css | 45 ++++++++++---------------------------------- 1 file changed, 10 insertions(+), 35 deletions(-) diff --git a/Templates/fastqc.css b/Templates/fastqc.css index 758cb0b..be9e5b9 100644 --- a/Templates/fastqc.css +++ b/Templates/fastqc.css @@ -258,7 +258,6 @@ body { border-top: 1px solid #EEE; font-size: 0.9rem; color: #666; - text-align: center; } /* Content styling */ @@ -309,12 +308,8 @@ tr:nth-child(even) td { /* Style Basic Statistics table (first module) to look like a definition list */ .module:first-of-type table { - border-collapse: separate; - border-spacing: 0; min-width: auto; - margin: 1rem 0; - width: auto; - max-width: 600px; + max-width: 100%; } .module:first-of-type table thead { @@ -322,44 +317,24 @@ tr:nth-child(even) td { } .module:first-of-type table tbody tr { - display: block; - margin-bottom: 1.5rem; - border: none; background: none; } - -.module:first-of-type table tbody td:first-child { - /* Style like definition list title (label above) */ - display: block; - font-weight: normal; +.module:first-of-type table td { font-family: sans-serif; background-color: transparent; - padding: 0; - border: none; - color: #666; - text-transform: uppercase; - font-size: 0.75rem; - letter-spacing: 0.8px; - margin-bottom: 0.25rem; - line-height: 1.2; } +.module:first-of-type table tbody td:first-child { + font-weight: bold; + color: #333; + text-align: right; + width: 12rem; +} .module:first-of-type table tbody td:last-child { - /* Style like definition list value (below label) */ - display: block; - font-family: sans-serif; - font-weight: normal; - background-color: transparent; - padding: 0; - margin: 0; - border: none; color: #000; - font-size: 1.1rem; - line-height: 1.3; } - -.module:first-of-type table tbody tr:nth-child(even) td { - background-color: transparent; +.module:first-of-type table tbody tr:last-child td { + border-bottom: none; } img { From e7f36622460e455cedaf28ec61877a7d63a22e7e Mon Sep 17 00:00:00 2001 From: Phil Ewels Date: Mon, 25 Aug 2025 10:21:33 +0200 Subject: [PATCH 09/27] New FastQC icon --- Templates/Icons/fastqc_icon.png | Bin 1197 -> 1232 bytes .../babraham/FastQC/Resources/fastqc_icon.png | Bin 1197 -> 1232 bytes .../babraham/FastQC/Resources/fastqc_icon.svg | 234 ++++-------------- .../FastQC/Resources/fastqc_icon_100.png | Bin 3470 -> 2157 bytes .../FastQC/Resources/fastqc_icon_hires.png | Bin 0 -> 53718 bytes 5 files changed, 46 insertions(+), 188 deletions(-) create mode 100644 uk/ac/babraham/FastQC/Resources/fastqc_icon_hires.png diff --git a/Templates/Icons/fastqc_icon.png b/Templates/Icons/fastqc_icon.png index 348c93b95df5645044fb8bf2cfb6be0e00ffe4c1..fb7b2cb7e9ea9eefd64a33d673a2aab5d01e2c26 100644 GIT binary patch literal 1232 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE3?yBabRA=0VB8bn6XFWwHoy>&mXMGDl5A{j zLPA2EoXS8c7BGM_n3$M=Y@iw-2}I1yKm(y{hzNws$jAuf0@*+YG8?EJA_$a)7{$se z05<{7U<9(j2uOhR1C=7#%gn+o&QJrCVqvJ&WGGi+sDdj7YeKjO$c0D&4Fs|wE&+-_ zltE;XNr){#l7XQSs0@gJ9t8Ul>Qj(oz%GZF5X2C|2zF^6g9}&$wqHi z3}rwvf*}EDAjl_7Oh6w&jRJZO2pJfH8Im-?%79#8kONf$V*yA4HJUJ_cre6fGFVqK z2=Fu1*fHb?)28^KrA)(Nq!_;s5vV&*zV?o}W2$XwUX_ zD;H0nI(0&IVNOm$u)njDou!3^k)e);in6@4lqAQ;m$#1W-LroEg8B33&hGDSX>Kac z%gabihz$?4)z{RJF4egTOm<9`o-U3d7N^$+rIrf^itM?0_gHM_?&Y4hD=sZ@=+!D+ zxYSLwygXfg%L(~s`#zj&3x2Wv+;rRDY2VJ(8gnn_d3~!Wpo^= z%0~rgHNF>f{i?KBy8mr$yTzl`1}3*%y5r8OKe%x4q>nzopwqsE57ZS8W$-A>-NNWD zE0M3>A+PbH)xT0uBZ?_pd-jZ(a=Yg*c;M!D;>X29%dRq9?-W~GqdrkyL+(ewg#2^5 z7ev3tmrbb=*YjMwa$#c)r$vqU^oROSE-vOyo*~Ln$lUVFb))goB!eSccQ0_}pV{7g zyCvmNz}ZXN%OWp^KAykg`0E{ywjNXJ-4$QHMyH4CyM^}&ORvSZl%}Qzym_nPaNYOy zvL@w;nigJ{RTfWgYP9vJ@R870ywC4?vtU}^>CbC)oG)EleSF^aWplza&#bGAz1q6J zr9b`q3xj36zm}Y3NT@Y;@VH-XvxaZ=^U5;rtdGxHw?B^zSlF`LBFSJ4(+cqi2khA$ zPIqN*w{z2a8l)f)xKZzr?+yJvu1}Ib*dIDJ2|SV9>9Dje>e{m`%MZVnZh!vh$lU0- z!|cWr74ED_jNCn|*UR$9x2wfd?#$P4%(-;##cN~UANpB!<>%&9@7Tb*yzze7{&hAl SW*p@MrF~CVKbLh*2~7Y)aF-7N delta 1188 zcmV;V1Y7&i39Si`8Gi-<0047(dh`GQ00eVFNmK|32nc)#WQYI&010qNS#tmY4c7nw z4c7reD4Tcy000?uMObuGZ)S9NVRB^vcXxL#X>MzCV_|S*E^l&Yo9;Xs000CkNklYU1%It6vuyOH*K0^H=CrU%~Bf`TZyqout8MRrVqZTRez}zMJ*OY9~2QGR@&6e z&YH$VMI?$~6_w(H(khY=1S?`ANWln7MWR$q{MxoD(XG*>n~&qe%%qdqyV*(Nfy>_g z-}CXGd(S=hh^n#_=@O~VL5spoz=gmCz%+0M7zREE1}xR_h5X233D_caz+T`XU{w+I zEYMR1&+k_Kdw^v)!@%0mMve?c;m&=k-x~>tNEKils``=}{2E{YC|zW5Pfi1y zE!E%rU?hxXw@3o`pg{0mf$b$wAB6^i`+;u^dTW3~h=?Bybp&aVHiZroHw*RB{4TIx&tNfnF*gJvJ0kq z3k3fc=(w39-vt-OsF@rm=J&sF5(3yF$AD}7*nbR>$4fa^aW20)4?^_b6i+9CeZj>l z{@RUG*tSCWQoK!}H;89Q@-FxIw{!xyEJdmjrxaHOOtL_|<$N%q2>{q4?*rR|_ylE) za1j}jB*`3WU}y@s9*721Rp5?x)jmJyJ;#+m+#Qub%>9i6aaDcwIg$7TdcPT#- zW5Jeh6lkj|>N_-EoS4)*|0`BZBGoBRi9PC|7=1{w7x zW7P07mvEd-WhqiG0$l;!N75o~g&cX6uzv#Q{EH4%eI59rfWJ)^?6qMXu+sw-I&6`Q zrJC0tcso#vllj#+&+j^%y1o%;#CgA)f$LoT0btfZU=OOAga?5mfwkAtBDV$&mXw45 zB6dH9o)6@9)%HGHWF^im@=MNA9dqpWuUBpRbr}Sn*$lIThNUSG8!qos-I4bmi+|Wx z18JZ_)!Mpb0&mXMGDl5A{j zLPA2EoXS8c7BGM_n3$M=Y@iw-2}I1yKm(y{hzNws$jAuf0@*+YG8?EJA_$a)7{$se z05<{7U<9(j2uOhR1C=7#%gn+o&QJrCVqvJ&WGGi+sDdj7YeKjO$c0D&4Fs|wE&+-_ zltE;XNr){#l7XQSs0@gJ9t8Ul>Qj(oz%GZF5X2C|2zF^6g9}&$wqHi z3}rwvf*}EDAjl_7Oh6w&jRJZO2pJfH8Im-?%79#8kONf$V*yA4HJUJ_cre6fGFVqK z2=Fu1*fHb?)28^KrA)(Nq!_;s5vV&*zV?o}W2$XwUX_ zD;H0nI(0&IVNOm$u)njDou!3^k)e);in6@4lqAQ;m$#1W-LroEg8B33&hGDSX>Kac z%gabihz$?4)z{RJF4egTOm<9`o-U3d7N^$+rIrf^itM?0_gHM_?&Y4hD=sZ@=+!D+ zxYSLwygXfg%L(~s`#zj&3x2Wv+;rRDY2VJ(8gnn_d3~!Wpo^= z%0~rgHNF>f{i?KBy8mr$yTzl`1}3*%y5r8OKe%x4q>nzopwqsE57ZS8W$-A>-NNWD zE0M3>A+PbH)xT0uBZ?_pd-jZ(a=Yg*c;M!D;>X29%dRq9?-W~GqdrkyL+(ewg#2^5 z7ev3tmrbb=*YjMwa$#c)r$vqU^oROSE-vOyo*~Ln$lUVFb))goB!eSccQ0_}pV{7g zyCvmNz}ZXN%OWp^KAykg`0E{ywjNXJ-4$QHMyH4CyM^}&ORvSZl%}Qzym_nPaNYOy zvL@w;nigJ{RTfWgYP9vJ@R870ywC4?vtU}^>CbC)oG)EleSF^aWplza&#bGAz1q6J zr9b`q3xj36zm}Y3NT@Y;@VH-XvxaZ=^U5;rtdGxHw?B^zSlF`LBFSJ4(+cqi2khA$ zPIqN*w{z2a8l)f)xKZzr?+yJvu1}Ib*dIDJ2|SV9>9Dje>e{m`%MZVnZh!vh$lU0- z!|cWr74ED_jNCn|*UR$9x2wfd?#$P4%(-;##cN~UANpB!<>%&9@7Tb*yzze7{&hAl SW*p@MrF~CVKbLh*2~7Y)aF-7N delta 1188 zcmV;V1Y7&i39Si`8Gi-<0047(dh`GQ00eVFNmK|32nc)#WQYI&010qNS#tmY4c7nw z4c7reD4Tcy000?uMObuGZ)S9NVRB^vcXxL#X>MzCV_|S*E^l&Yo9;Xs000CkNklYU1%It6vuyOH*K0^H=CrU%~Bf`TZyqout8MRrVqZTRez}zMJ*OY9~2QGR@&6e z&YH$VMI?$~6_w(H(khY=1S?`ANWln7MWR$q{MxoD(XG*>n~&qe%%qdqyV*(Nfy>_g z-}CXGd(S=hh^n#_=@O~VL5spoz=gmCz%+0M7zREE1}xR_h5X233D_caz+T`XU{w+I zEYMR1&+k_Kdw^v)!@%0mMve?c;m&=k-x~>tNEKils``=}{2E{YC|zW5Pfi1y zE!E%rU?hxXw@3o`pg{0mf$b$wAB6^i`+;u^dTW3~h=?Bybp&aVHiZroHw*RB{4TIx&tNfnF*gJvJ0kq z3k3fc=(w39-vt-OsF@rm=J&sF5(3yF$AD}7*nbR>$4fa^aW20)4?^_b6i+9CeZj>l z{@RUG*tSCWQoK!}H;89Q@-FxIw{!xyEJdmjrxaHOOtL_|<$N%q2>{q4?*rR|_ylE) za1j}jB*`3WU}y@s9*721Rp5?x)jmJyJ;#+m+#Qub%>9i6aaDcwIg$7TdcPT#- zW5Jeh6lkj|>N_-EoS4)*|0`BZBGoBRi9PC|7=1{w7x zW7P07mvEd-WhqiG0$l;!N75o~g&cX6uzv#Q{EH4%eI59rfWJ)^?6qMXu+sw-I&6`Q zrJC0tcso#vllj#+&+j^%y1o%;#CgA)f$LoT0btfZU=OOAga?5mfwkAtBDV$&mXw45 zB6dH9o)6@9)%HGHWF^im@=MNA9dqpWuUBpRbr}Sn*$lIThNUSG8!qos-I4bmi+|Wx z18JZ_)!Mpb0 - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - C - - - - - - - Q - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/uk/ac/babraham/FastQC/Resources/fastqc_icon_100.png b/uk/ac/babraham/FastQC/Resources/fastqc_icon_100.png index 668c917987e41e9fba52e0e09f98f70eec4c5c3d..43e0a8e142c9f17724900930dcb5817b788398a7 100644 GIT binary patch literal 2157 zcmYjSdpwhS82>SI9cJdTxed{ld!aBg<}!DiT+7JysBj!f?$_hqq=_z5riM}-6{fh3?4J zM-m313o$Ah01<|dho2Las-RF(Qd00AAu1{ggTWva5*W-?Kgu8|Q8~~vAfe@-f_>-)q ztLuJ_6&i$=pUxkmu<^h4HP70lRbln4CI2BbFbg1r3KnF*epLVO6fQLbNf|%~3)1yK zs?Z+{f_?>CGJt{>$UuV(d$4Ce(8YrkOYmzX@Z1eZ(jdzlL>R(ix&Qzv$y6^IfXkqf zSiG*~MkC2k8+#3M_FfZDEeXoUIjR$Su{B`)m_b>P9!}+Ab6s52J09=%f>@oG564FP znT)c87%%MvQ)9fo?1T0;b6LU1{uXxTzA#(j^zgN&T+3V6yI9PMG`i~+3pLEwxf_Z9 zG%$mM{FG*RHxVl8UjPtSp^!;_u}>C`@aZU$>VV2p=t8ib2M%?Q-L&*dv_KbRMUZ~$e&}4Vr$MeHZI3K zPRtAl*bzfh!;X9bjtuLE2q~Y({`AR554lM*QzH*TI*uJnurcYa6;-~x*e-fCm_Av6 zI}vxU=ZbtFwROz$l)r{MI2)Ipps3U2Xce~OdeFO0n_Y3+spF@QPg+P-$X29aig(hx zy6ZA@moXalF1d+W7U&lhqqgHA!|j<@@1CcTJ8PZxN{=+{7{qh&f4TI#?Z<~#2`xrkNCMO3HJ39-M%2F-#%dHV--bvUGCcIEQ-EtW(|5Rjq9WrKJ2PZ8h zu=rHy(6yqlJ}bqALleV^ojB6*wA_{?&QaKvXjxn()yB}XmP^>`rij@;aKyl~WyWfh z?NIQ&Hhug{L=OLDQvKt07gfEIt+fZ#MLe>}zIVh989Gnh3}m|Udb0SNJ4V5{Noz|X zW47|jeS6Cq{l1G!J_o$XK^WmUl-H~j69X4AFOf)yeg@?vWBn^2lRWUb5t}7y+ zN&tLG+d9d&OpH>^-!cyq8O4Nf?z<0)T7mQW+79_ddT8e~<~}>>AeUe-a4vs8Rykq8 zF-*^S--FYb&}m)-{BrfumS=D(a^A?SWo)oCI6RBE;wcB;`)$;aKvqwl^{z#rP&3JB z^oVwdhq&6?gU*O*J2m?}WyFmOG>Q(kx9{?EtKC}5>bEp6s{YmT`E!Kt&A@^-ZpDc} z4fPv}zL>#s+km1!tqYxJ{>axljd#u^d%PapQ`L^zYch?PdK2F%nQl@3W=~$Lt)o`_ z*U}vdFp|$g@4jo5;ujrEQ)sa=9Oc_bSDHhunLBQ^r98!hhv&ynQ zPKn*lzPLHL#QqO4yNYQ_;+D}eLl?6BwjS@s!FetDp$&Bk?d5xB4zx-Fz(F}Wu`<)aOUxXvc8TYRDKm+EH?Q@H4CYJPhdQTeJny%%Rw+DLpZ!SffSis&iU ztgkofj?zt=1I<_3Zj0)nFSMH&xh;5#=kIo_z8vsHduu~ffrf4;A&Gs?y`hA7;FvILIBogT+O4JLbMLc(h^RN9Bx8)nt> zj~i^2STwkd_LhjD^T|1GrJrOpBf_1?Xz~2!gWG*4npuqHULK#Orguc2>(H22%r@-sc0(0yS?6^x&$Y>wZ4W98H5OO1>R$l9vn zm*E}1=WW`_vqq9slIBJ)`Pca3r{k+m-O+YNeuHm7Vc))Z(xqnP#Z+=QSlh$%QijJV zBz=6%n;XeP1S2U?G;2cfhX(#Sx+HVNxPIMXv0YtzU(z-`r`VU^wHJT$A)GPexmQVE zudJ_%4uG?i)1&GF=J;V!D`lmG+w24Sn;!AI`0(VD&6U%Gr5@Y7o~bPOY$Sem00PYi z8AAf@mk&#sxcAwIaISh`E%o7Dp($k*f%@`XPJdu;!V|mw8@FsRHN_3K8U~5_)Wos! zlm=gtW~{Sg#!(S?r^PqB2jNk65xJz$wWR3#`nyp!-+ otK_N2=-7H%ksS0L7n~5tWEnVoD+{@_1pTA{#mS3&-XSdSU%WC`mH+?% literal 3470 zcmV;94RP{`P)%frY)*m=1xz*;ly&3of_!w9YECk*L-t|B!HWM zsh(=HE1@Mvh!Lp{i(2af}nd#WFYxyjh7dKPdAyYn6wTYw|N zc8AkSh+1|E)$O_rcVw&rCV8q)MY-8i-2hB9BKHGxfdLNk)Crgl{3OgxMd|h$ksjE_ zud4%bYk=W#dN!?LMD_(<1&(weE&&YoRNo7FLxqEfM!^-hA>#{d-`@!t0Lk9b2w;T+ zaTSDYBMV+alB$va0S7n`cZ#R_k^?zyU__1p-Xnfv-wYh$sjd!^xELj5EN;knBwu6z zc&Z-)vmJ=4!gdw{p%{c*=s?C6;3@}la$yGWsRKFZ22EH{LXs*H7mCB%JXIHeRJ-t0 zw*b=|h#Fu-`UOc?=n^slsBs|YJ_j;_Vm@}X9~WbSBq}r^BOS60r_n(9PE zs<3r@Rq|SU`_!@jcbmPc&cQmf#ce-!0I{udVd1H6H6qJ^!()mXOpacgU)x)a9YJTa zb99P$JO?-|=F0#qcIi+M5{rmW$RW8B6tWFD$bpP^9mt4^e>sqm^FQ#HkX_g=UIIJh zZ^913YOtlJHhJvda-9#9nE+VkKt@!!(3gcHM6H8yzMPC*s7p3EkP#Id9mv=(SAs%T zSuRYbn;poAigq0}0wR|;enCyRE(pnM2@x^9fx#dHKo7ed!?;OVylzvmsSaJ;l>}kiWQmF1DeNyUOV!69szNsE zTO7y;JyS|#<^dw+F6=nsd?JtmQ0t)c*^v%}arw z60yi1R~~W;2C^hUR?BGeQX(<0~GK=R#`3x8Q9)Mk%m#gYd9tY-~cjuq=v#;vih92 zppb;P&;=ct^p>Nes_IF=huDTa z&WODRs{&t~p6`ZJKp*wLk1N!%jry3HlV+;eK=+*K{4Y>}H7wO&|4di*5IoggM&uph zPi-DSD?&u34+MP*H_j6o(VwNUWvpXAG=Lv>p>68_a3G__$4SI=hQy=fZ?4BW;GvUw z>4Ug}mS^=V?~taa@t2V8z4{XRlPIP$&lW_ z@=|(@GimFb17C0K@ zO0w8?3QmZp`ZB(5YZM&KyBtXD;0bG?a=5DZH~$4AavE?>+y`JI2rWweQ1y1IPQ4YX z4#&F0rs?&IHG^srHr!DxY^5W=V_cvCR|Y6BTGe|lL;i+ggBZB5N)7c?-wc|#STm^R zVnZFpLPxf80ry4KGu@Vjj6v9T&IK8N4nqbMi4ae92XKuGS)KWki@BF?@lKfA-iPjK zjkOV}Fd~-&uj6LAT>?7?KNN}<>%`b8*slO5xRSYoLwSJ_d`d1CS~*vB>cg$_F&wxV z80so7z)ha&)nRWcYVet4fU@^+922XNdX_MNW%Q$wdcLG{i<3e}wyvJU-J?6Pxfj;C z;Y`TMU|1{yh9ql(P$+sdAR}@P1(;%xpaMmxWLLf))r2J@lIv-)8ub=9o-562wIlX47?F8|jCxRFP~Z|zHP*n_uUxFhYEJ8N zY_$Q>WZRC#&Qtee0#;{qL7W#VB7PB<3@CvrD+Nz=r>A-$FtgZs35o5%#h&V&E`*f~ zAt`vOQ?R9^n2yy!u@pGYQ=R8ZV5T<2A7;tFWxE#i{Q9Jtzg-xS!?2SrzZ31%@{ak~ z2HdT`ak0C-?ZMa&_NHiXRV1)7`Dufa8;4|p zi^)DfRk!52ALD=*BMRvSJeQ0c=^SN2h^n^}9Jrs;+zna`WMhdQh+qKlv=MPK@vt?@ zf{-LuIFRv;)Il=r(x@16j{_b_E=uMMdmACcTL17=*I)j7OAziUHi)wZUoGHfsR#m+rEu-@5KCsipvO?#ndKpc|Mr1tj z+lX>^0b@PYSm6N6rpi*C@+ri3Rm84?m=T`pT)>Mcw-VdPx2YDxplk?9!bLF3p(4|> zy8C#l4M5bYrw;gIGAec?_)WN*fG^2yGtbAC`Zy}E4$v7OkAY5#`m(!`xC$H5AsZ%P zlL=*^I!Qs~(Mnjn3Zgml`f!%2H$U4&W9M5=Ci+ylMV@MC z_olKU1VF^h0H!z)wGkMk>Sc1cC>qMG4FRg|z^cOIqAT#A$nANXESd`<=4_E!X;J3N zju6#rSL4ppaX4&vUgXAtF7GO0juJ610uRHEvF=PO6)QlRaw)PTce(Wh^fVT&c_XI z?8gVdWbmF*jcyYbxu*)&j0F8Ta4Ok9{=-zg6)pFbD?IuzRh_c3MNT;r0w7{0K>To_0k8!d*SLB!0)uKZSxNF$^y8+AWay(_U3Ny{Go@Jt=qy#z&Nmc9R6rgXWk zhux=+m#gY;vb@VgtWNCW$p1zOAk%UcDZ4~fmc9R6wsiT}zXfC@MAb_G<3-F0?2@Nt zi9MpqY7JFy2G-}QXimU!u*VSspz1vW9R^aI<&k2cO)o3Cgm;^C+3pW<-h~X+5L1ms z5NH?&+JFtJUut**7^Uj9EQPU0bbE6lIjX-D_!ZIpdR<``@B~!MR=xi3{)>ABAt_i@ z`-U@tpAkRyV^}N)9*4?1RjI}P5 wA#bapVlyNfp{5a<8k1unH_!ZvkkZ2c0q6!G-Q6*$SpWb407*qoM6N<$g5JP6vH$=8 diff --git a/uk/ac/babraham/FastQC/Resources/fastqc_icon_hires.png b/uk/ac/babraham/FastQC/Resources/fastqc_icon_hires.png new file mode 100644 index 0000000000000000000000000000000000000000..a77b12e1a5dba5d2ea3868a15de0c4aec4123cbb GIT binary patch literal 53718 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 literal 0 HcmV?d00001 From 90c8a270a888429c939585da4628c13b84d8ecb6 Mon Sep 17 00:00:00 2001 From: Phil Ewels Date: Mon, 25 Aug 2025 10:37:16 +0200 Subject: [PATCH 10/27] Use SVG icon instead of PNG --- Templates/Icons/fastqc_icon.svg | 47 +++++++++++++++++++ Templates/fastqc.css | 6 ++- Templates/report_template.html | 4 +- .../FastQC/Report/HTMLReportArchive.java | 47 +++++-------------- 4 files changed, 65 insertions(+), 39 deletions(-) create mode 100644 Templates/Icons/fastqc_icon.svg diff --git a/Templates/Icons/fastqc_icon.svg b/Templates/Icons/fastqc_icon.svg new file mode 100644 index 0000000..618ccb4 --- /dev/null +++ b/Templates/Icons/fastqc_icon.svg @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Templates/fastqc.css b/Templates/fastqc.css index be9e5b9..8c7a7e5 100644 --- a/Templates/fastqc.css +++ b/Templates/fastqc.css @@ -100,7 +100,8 @@ body { min-width: 0; /* Allow shrinking */ } -.mobile-icon { +.mobile-icon, +.mobile-title svg { height: 20px; width: 20px; flex-shrink: 0; @@ -146,7 +147,8 @@ body { gap: 0.5rem; } -.header-title img { +.header-title img, +.header-title svg { height: 24px; width: auto; margin: 0; diff --git a/Templates/report_template.html b/Templates/report_template.html index 6ae00c1..0e0e545 100644 --- a/Templates/report_template.html +++ b/Templates/report_template.html @@ -19,7 +19,7 @@
    - FastQC + {{FASTQC_ICON_SVG_MOBILE}} FastQC: {{FILENAME}}
    @@ -30,7 +30,7 @@