mirror of
https://github.com/Stirling-Tools/Stirling-PDF.git
synced 2025-06-06 09:12:02 +00:00
Homepage update (#2663)
# Description Please provide a summary of the changes, including relevant motivation and context. Closes #(issue_number) ## Checklist - [ ] I have read the [Contribution Guidelines](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/CONTRIBUTING.md) - [ ] I have performed a self-review of my own code - [ ] I have attached images of the change if it is UI based - [ ] I have commented my code, particularly in hard-to-understand areas - [ ] If my code has heavily changed functionality I have updated relevant docs on [Stirling-PDFs doc repo](https://github.com/Stirling-Tools/Stirling-Tools.github.io/blob/main/docs/) - [ ] My changes generate no new warnings - [ ] I have read the section [Add New Translation Tags](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/HowToAddNewLanguage.md#add-new-translation-tags) (for new translation tags only) --------- Co-authored-by: Reece Browne <reece@stirling.pdf>
This commit is contained in:
parent
67569a8f6a
commit
60cc613c63
@ -74,6 +74,12 @@ public class HomeWebController {
|
||||
return "redirect:/";
|
||||
}
|
||||
|
||||
@GetMapping("/home-legacy")
|
||||
public String homeLegacy(Model model) {
|
||||
model.addAttribute("currentPage", "home-legacy");
|
||||
return "home-legacy";
|
||||
}
|
||||
|
||||
@GetMapping(value = "/robots.txt", produces = MediaType.TEXT_PLAIN_VALUE)
|
||||
@ResponseBody
|
||||
@Hidden
|
||||
|
@ -138,6 +138,7 @@ analytics.settings=You can change the settings for analytics in the config/setti
|
||||
# NAVBAR #
|
||||
#############
|
||||
navbar.favorite=Favorites
|
||||
navbar.recent=New and recently updated
|
||||
navbar.darkmode=Dark Mode
|
||||
navbar.language=Languages
|
||||
navbar.settings=Settings
|
||||
@ -265,6 +266,14 @@ home.viewPdf.title=View PDF
|
||||
home.viewPdf.desc=View, annotate, add text or images
|
||||
viewPdf.tags=view,read,annotate,text,image
|
||||
|
||||
home.setFavorites=Set Favourites
|
||||
home.hideFavorites=Hide Favourites
|
||||
home.showFavorites=Show Favourites
|
||||
home.legacyHomepage=Old homepage
|
||||
home.newHomePage=Try our new homepage!
|
||||
home.alphabetical=Alphabetical
|
||||
home.globalPopularity=Global Popularity
|
||||
|
||||
home.multiTool.title=PDF Multi Tool
|
||||
home.multiTool.desc=Merge, Rotate, Rearrange, Split, and Remove pages
|
||||
multiTool.tags=Multi Tool,Multi operation,UI,click drag,front end,client side,interactive,intractable,move,delete,migrate,divide
|
||||
@ -1007,8 +1016,8 @@ multiTool.moveLeft=Move Left
|
||||
multiTool.moveRight=Move Right
|
||||
multiTool.delete=Delete
|
||||
multiTool.dragDropMessage=Page(s) Selected
|
||||
multiTool.undo=Undo
|
||||
multiTool.redo=Redo
|
||||
multiTool.undo=Undo (CTRL + Z)
|
||||
multiTool.redo=Redo (CTRL + Y)
|
||||
|
||||
#decrypt
|
||||
decrypt.passwordPrompt=This file is password-protected. Please enter the password:
|
||||
|
@ -12,10 +12,14 @@
|
||||
bottom: 0;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.navbar {
|
||||
height: auto; /* Adjusts height automatically based on content */
|
||||
white-space: nowrap; /* Prevents wrapping of navbar contents */
|
||||
height: auto;
|
||||
/* Adjusts height automatically based on content */
|
||||
white-space: nowrap;
|
||||
/* Prevents wrapping of navbar contents */
|
||||
}
|
||||
|
||||
/* TODO enable later
|
||||
.navbar .container {
|
||||
|
||||
@ -28,10 +32,12 @@
|
||||
html[dir="ltr"] * {
|
||||
direction: ltr;
|
||||
}
|
||||
|
||||
html[dir="rtl"] * {
|
||||
direction: rtl;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.ignore-rtl {
|
||||
direction: ltr !important;
|
||||
text-align: left !important;
|
||||
@ -41,6 +47,7 @@ html[dir="rtl"] * {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
}
|
||||
|
||||
.align-center-right {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
@ -58,7 +65,7 @@ html[dir="rtl"] * {
|
||||
bottom: 0;
|
||||
}
|
||||
|
||||
.btn-group > label:first-of-type {
|
||||
.btn-group>label:first-of-type {
|
||||
border-top-left-radius: 0.25rem !important;
|
||||
border-bottom-left-radius: 0.25rem !important;
|
||||
}
|
||||
@ -67,6 +74,7 @@ html[dir="rtl"] input.form-check-input {
|
||||
position: relative;
|
||||
margin-left: 0px;
|
||||
}
|
||||
|
||||
html[dir="rtl"] label.form-check-label {
|
||||
display: inline;
|
||||
}
|
||||
@ -75,70 +83,58 @@ html[dir="rtl"] label.form-check-label {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.margin-center {
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
#pdf-canvas {
|
||||
box-shadow: 0px 0px 8px rgba(0, 0, 0, 0.384);
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.fixed-shadow-canvas {
|
||||
box-shadow: 0px 0px 8px rgba(0, 0, 0, 0.384);
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.shadow-canvas {
|
||||
box-shadow: 0px 0px 8px rgba(0, 0, 0, 0.384);
|
||||
}
|
||||
|
||||
.hidden {
|
||||
display: none;
|
||||
}
|
||||
|
||||
input:-webkit-autofill,
|
||||
input:-webkit-autofill:focus {
|
||||
transition: background-color 600000s 0s, color 600000s 0s;
|
||||
transition: background-color 600000s 0s, color 600000s 0s;
|
||||
}
|
||||
|
||||
input[data-autocompleted] {
|
||||
background-color: transparent !important;
|
||||
background-color: transparent !important;
|
||||
}
|
||||
|
||||
.btn-tooltip {
|
||||
position: absolute;
|
||||
position: absolute !important;
|
||||
display: none;
|
||||
bottom: 3.2rem;
|
||||
white-space: nowrap;
|
||||
flex-wrap: nowrap;
|
||||
width: fit-content;
|
||||
padding: 7px;
|
||||
background-color: rgba(0, 29, 41, 0.9);
|
||||
border-radius: 3px;
|
||||
font-size: 12px;
|
||||
color: whitesmoke;
|
||||
animation: fadeup 0.15s linear;
|
||||
z-index: 10000;
|
||||
}
|
||||
|
||||
@keyframes fadeup {
|
||||
0% {
|
||||
transform: translateY(10px);
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
100% {
|
||||
transform: translateY(0);
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
.btn:hover .btn-tooltip {
|
||||
display: block;
|
||||
}
|
||||
.btn-primary:hover .btn-tooltip {
|
||||
display: block;
|
||||
}
|
||||
.btn-success:hover .btn-tooltip {
|
||||
display: block;
|
||||
}
|
||||
.btn-secondary:hover .btn-tooltip {
|
||||
display: block;
|
||||
}
|
||||
.btn-toolbarButton:hover .btn-tooltip {
|
||||
display: block;
|
||||
}
|
||||
.toolbarButton:hover .btn-tooltip {
|
||||
display: block;
|
||||
}
|
||||
|
229
src/main/resources/static/css/home-legacy.css
Normal file
229
src/main/resources/static/css/home-legacy.css
Normal file
@ -0,0 +1,229 @@
|
||||
#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;
|
||||
}
|
||||
|
||||
.features-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 30px;
|
||||
}
|
||||
|
||||
.feature-group-legacy {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.feature-group-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
color: var(--md-sys-color-on-surface);
|
||||
margin-bottom: 15px;
|
||||
user-select: none;
|
||||
cursor: pointer;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.feature-group-container {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(15rem, 3fr));
|
||||
gap: 30px 30px;
|
||||
overflow: hidden;
|
||||
margin: -20px;
|
||||
padding: 20px;
|
||||
box-sizing:content-box;
|
||||
}
|
||||
|
||||
.feature-group-container.animated-group {
|
||||
transition: 0.5s all;
|
||||
}
|
||||
|
||||
.feature-group-legacy.collapsed>.feature-group-container {
|
||||
max-height: 0 !important;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.header-expand-button {
|
||||
transition: 0.5s all;
|
||||
transform: rotate(90deg);
|
||||
}
|
||||
|
||||
.header-expand-button.collapsed {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
|
||||
.feature-card {
|
||||
border: 1px solid var(--md-sys-color-surface-5);
|
||||
border-radius: 1.75rem;
|
||||
padding: 1.25rem;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
background: var(--md-sys-color-surface-5);
|
||||
transition:
|
||||
transform 0.3s,
|
||||
border 0.3s;
|
||||
transform-origin: center center;
|
||||
outline: 0px solid transparent;
|
||||
position:relative;
|
||||
}
|
||||
|
||||
.feature-card a {
|
||||
text-decoration: none;
|
||||
color: var(--md-sys-color-on-surface);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.feature-card .card-text {
|
||||
font-size: .875rem;
|
||||
}
|
||||
|
||||
.feature-card:hover {
|
||||
cursor: pointer;
|
||||
transform: scale(1.08);
|
||||
box-shadow: var(--md-sys-elevation-2);
|
||||
}
|
||||
|
||||
.card-title.text-primary {
|
||||
color: #000;
|
||||
}
|
||||
|
||||
.home-card-icon {
|
||||
width: 3rem;
|
||||
height: 3rem;
|
||||
transform: translateY(-5px);
|
||||
}
|
||||
|
||||
.favorite-icon {
|
||||
display: none !important;
|
||||
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;
|
||||
}
|
||||
|
||||
.card-title {
|
||||
margin-bottom: 1rem;
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
|
||||
/* Only show the favorite icons when the parent card is being hovered over */
|
||||
.feature-card:hover .favorite-icon {
|
||||
display: block !important;
|
||||
}
|
||||
|
||||
.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);
|
||||
}
|
||||
|
||||
@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;
|
||||
}
|
@ -36,101 +36,6 @@
|
||||
border: 0.1rem solid transparent;
|
||||
}
|
||||
|
||||
.features-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 30px;
|
||||
}
|
||||
|
||||
.feature-group {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.feature-group-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
color: var(--md-sys-color-on-surface);
|
||||
margin-bottom: 15px;
|
||||
user-select: none;
|
||||
cursor: pointer;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.feature-group-container {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(15rem, 3fr));
|
||||
gap: 30px 30px;
|
||||
overflow: hidden;
|
||||
margin: -20px;
|
||||
padding: 20px;
|
||||
box-sizing:content-box;
|
||||
}
|
||||
|
||||
.feature-group-container.animated-group {
|
||||
transition: 0.5s all;
|
||||
}
|
||||
|
||||
.feature-group.collapsed>.feature-group-container {
|
||||
max-height: 0 !important;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.header-expand-button {
|
||||
transition: 0.5s all;
|
||||
transform: rotate(90deg);
|
||||
}
|
||||
|
||||
.header-expand-button.collapsed {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
|
||||
.feature-card {
|
||||
border: 1px solid var(--md-sys-color-surface-5);
|
||||
border-radius: 1.75rem;
|
||||
padding: 1.25rem;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
background: var(--md-sys-color-surface-5);
|
||||
transition:
|
||||
transform 0.3s,
|
||||
border 0.3s;
|
||||
transform-origin: center center;
|
||||
outline: 0px solid transparent;
|
||||
}
|
||||
|
||||
.feature-card a {
|
||||
text-decoration: none;
|
||||
color: var(--md-sys-color-on-surface);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.feature-card .card-text {
|
||||
font-size: .875rem;
|
||||
}
|
||||
|
||||
.feature-card:hover {
|
||||
cursor: pointer;
|
||||
transform: scale(1.08);
|
||||
box-shadow: var(--md-sys-elevation-2);
|
||||
}
|
||||
|
||||
.card-title.text-primary {
|
||||
color: #000;
|
||||
}
|
||||
|
||||
.home-card-icon {
|
||||
width: 3rem;
|
||||
height: 3rem;
|
||||
transform: translateY(-5px);
|
||||
}
|
||||
|
||||
.favorite-icon {
|
||||
display: none;
|
||||
position: absolute;
|
||||
@ -147,16 +52,6 @@
|
||||
margin: 0.0rem 0 0 1.25rem;
|
||||
}
|
||||
|
||||
.card-title {
|
||||
margin-bottom: 1rem;
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
|
||||
/* Only show the favorite icons when the parent card is being hovered over */
|
||||
.feature-card:hover .favorite-icon {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.favorite-icon img {
|
||||
filter: brightness(0) invert(var(--md-theme-filter-color));
|
||||
}
|
||||
@ -195,34 +90,21 @@
|
||||
animation: 2s infinite Pulse steps(20);
|
||||
}
|
||||
|
||||
@keyframes Pulse {
|
||||
from {
|
||||
opacity: 0;
|
||||
}
|
||||
.newfeature{
|
||||
min-width:12rem;
|
||||
}
|
||||
.recent-features{
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
max-width: 100%;
|
||||
overflow: hidden;
|
||||
justify-content: center;
|
||||
|
||||
50% {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
to {
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.update-notice {
|
||||
animation: scale 1s infinite alternate;
|
||||
.close-icon {
|
||||
color: var(--favourite-remove) !important;
|
||||
}
|
||||
|
||||
@keyframes scale {
|
||||
0% {
|
||||
transform: scale(0.96);
|
||||
}
|
||||
|
||||
100% {
|
||||
transform: scale(1);
|
||||
}
|
||||
}
|
||||
|
||||
.hidden {
|
||||
visibility: hidden;
|
||||
.add-icon {
|
||||
color: var(--favourite-add) !important;
|
||||
}
|
||||
|
@ -231,6 +231,13 @@ span.icon-text::after {
|
||||
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 {
|
||||
@ -302,7 +309,7 @@ span.icon-text::after {
|
||||
padding: 1.5rem 0;
|
||||
border-radius: 1rem;
|
||||
color: var(--md-sys-color-on-surface);
|
||||
background-color: var(--md-sys-color-surface-container);
|
||||
background-color: var(--md-sys-color-surface);
|
||||
border: 1px solid var(--md-sys-color-surface-5);
|
||||
box-shadow: var(--md-sys-elevation-2);
|
||||
}
|
||||
@ -342,12 +349,12 @@ span.icon-text::after {
|
||||
}
|
||||
|
||||
.go-pro-link {
|
||||
position: relative;
|
||||
padding: 0.5rem 1rem;
|
||||
transition: all 0.3s ease;
|
||||
z-index: 1;
|
||||
display: inline-block;
|
||||
width: auto;
|
||||
position: relative;
|
||||
padding: 0.5rem 1rem;
|
||||
transition: all 0.3s ease;
|
||||
z-index: 1;
|
||||
display: inline-block;
|
||||
width: auto;
|
||||
}
|
||||
|
||||
.go-pro-badge {
|
||||
@ -371,6 +378,114 @@ span.icon-text::after {
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
#stacked > .navbar-item {
|
||||
#stacked>.navbar-item {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.features-container {
|
||||
display: flex;
|
||||
gap: 30px;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.feature-group {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-width: 14rem;
|
||||
max-width: 18rem;
|
||||
flex: 1 1 min(14rem, 100%);
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.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;
|
||||
}
|
||||
|
@ -187,7 +187,7 @@ html {
|
||||
#apply-redaction:is(:hover):not([disabled=true], :disabled:not([disabled=false])) {
|
||||
cursor: pointer;
|
||||
background-color: rgba(6, 114, 197, 0.82);
|
||||
color: rgb(255 255 255);
|
||||
color: rgb(14, 12, 12);
|
||||
outline:rgba(6, 114, 197, 0.82) !important;
|
||||
border-color: rgba(6, 114, 197, 0.82) !important;
|
||||
}
|
||||
@ -230,8 +230,14 @@ html {
|
||||
.splitToolbarButton > .btn-primary, .splitToolbarButton > .btn-secondary, .splitToolbarButton > .toolbarButton {
|
||||
margin-left: 3px;
|
||||
margin-right: 3px;
|
||||
border:none
|
||||
}
|
||||
|
||||
.splitToolbarButton > .btn-success, .splitToolbarButton > .btn-secondary, .splitToolbarButton > .toolbarButton {
|
||||
border:none
|
||||
}
|
||||
|
||||
|
||||
.spin-animation {
|
||||
-webkit-animation: spin 2s linear infinite; /* Safari */
|
||||
-moz-animation: spin 2s linear infinite;
|
||||
|
@ -128,6 +128,13 @@ td {
|
||||
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);
|
||||
@ -213,6 +220,11 @@ td {
|
||||
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);
|
||||
@ -874,6 +886,8 @@ textarea.form-control {
|
||||
.dropdown-item {
|
||||
color: var(--md-sys-color-on-surface);
|
||||
padding: 0.25rem 1rem;
|
||||
border-radius: 3rem;
|
||||
|
||||
}
|
||||
|
||||
.dropdown-item:focus,
|
||||
@ -881,9 +895,15 @@ textarea.form-control {
|
||||
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);
|
||||
}
|
||||
.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 {
|
||||
|
@ -2,11 +2,11 @@
|
||||
.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, 0, 0.05) 5%);
|
||||
--md-sys-color-surface-2: color-mix(in srgb, var(--md-sys-color-primary) 13%, rgba(0, 0, 0, 0.08) 5%);
|
||||
--md-sys-color-surface-3: color-mix(in srgb, var(--md-sys-color-primary) 13%, rgba(0, 0, 0, 0.11) 5%);
|
||||
--md-sys-color-surface-4: color-mix(in srgb, var(--md-sys-color-primary) 13%, rgba(0, 0, 0, 0.12) 5%);
|
||||
--md-sys-color-surface-5: color-mix(in srgb, var(--md-sys-color-primary) 13%, rgba(0, 0, 0, 0.14) 5%);
|
||||
--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%);
|
||||
/* Icon fill */
|
||||
--md-sys-icon-fill-0: 'FILL' 0, 'wght' 500;
|
||||
--md-sys-icon-fill-1: 'FILL' 1, 'wght' 500;
|
||||
|
@ -58,6 +58,8 @@
|
||||
--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));
|
||||
@ -70,4 +72,8 @@
|
||||
--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-seperator: rgb(24 28 34);
|
||||
--md-nav-background: rgb(15 20 26);
|
||||
--favourite-add: #9ed18c;
|
||||
--favourite-remove: palevioletred;
|
||||
}
|
||||
|
@ -19,8 +19,8 @@
|
||||
--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(248 249 255);
|
||||
--md-sys-color-on-surface: 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);
|
||||
@ -58,6 +58,8 @@
|
||||
--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));
|
||||
@ -70,4 +72,8 @@
|
||||
--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-seperator: rgb(174, 178, 179);
|
||||
--md-nav-background: rgb(248 249 255);
|
||||
--favourite-add: #25ab6c;
|
||||
--favourite-remove: rgb(222, 94, 137);
|
||||
}
|
||||
|
66
src/main/resources/static/files/popularity.txt
Normal file
66
src/main/resources/static/files/popularity.txt
Normal file
@ -0,0 +1,66 @@
|
||||
{
|
||||
"/login": 1,
|
||||
"/multi-tool": 2,
|
||||
"/merge-pdfs": 3,
|
||||
"/pdf-to-word": 4,
|
||||
"/compress-pdf": 5,
|
||||
"/pdf-to-img": 6,
|
||||
"/pipeline": 7,
|
||||
"/split-pdfs": 8,
|
||||
"/img-to-pdf": 9,
|
||||
"/file-to-pdf": 10,
|
||||
"/ocr-pdf": 11,
|
||||
"/sign": 12,
|
||||
"/remove-password": 13,
|
||||
"/adjust-contrast": 14,
|
||||
"/pdf-to-text": 15,
|
||||
"/extract-page": 16,
|
||||
"/add-watermark": 17,
|
||||
"/remove-pages": 18,
|
||||
"/crop": 19,
|
||||
"/url-to-pdf": 20,
|
||||
"/pdf-to-presentation": 21,
|
||||
"/pdf-to-csv": 22,
|
||||
"/html-to-pdf": 23,
|
||||
"/cert-sign": 24,
|
||||
"/rotate-pdf": 25,
|
||||
"/console/": 26,
|
||||
"/geoserver": 27,
|
||||
"/pdf-to-xml": 28,
|
||||
"/markdown-to-pdf": 29,
|
||||
"/pdf-organizer": 30,
|
||||
"/add-image": 31,
|
||||
"/stamp": 32,
|
||||
"/auto-redact": 33,
|
||||
"/scale-pages": 34,
|
||||
"/extract-images": 35,
|
||||
"/change-metadata": 36,
|
||||
"/pdf-to-html": 37,
|
||||
"/get-info-on-pdf": 38,
|
||||
"/replace-and-invert-color-pdf": 39,
|
||||
"/pdf-to-pdfa": 40,
|
||||
"/change-permissions": 41,
|
||||
"/compare": 42,
|
||||
"/add-password": 43,
|
||||
"/multi-page-layout": 44,
|
||||
"/add-page-numbers": 45,
|
||||
"/auto-rename": 46,
|
||||
"/auto-split-pdf": 47,
|
||||
"/extract-image-scans": 48,
|
||||
"/flatten": 49,
|
||||
"/overlay-pdf": 50,
|
||||
"/pdf-to-markdown": 51,
|
||||
"/pdf-to-single-page": 52,
|
||||
"/redact": 53,
|
||||
"/remove-annotations": 54,
|
||||
"/remove-blanks": 55,
|
||||
"/remove-cert-sign": 56,
|
||||
"/remove-image-pdf": 57,
|
||||
"/repair": 58,
|
||||
"/sanitize-pdf": 59,
|
||||
"/show-javascript": 60,
|
||||
"/split-by-size-or-count": 61,
|
||||
"/split-pdf-by-chapters": 62,
|
||||
"/split-pdf-by-sections": 63,
|
||||
"/validate-signature": 64
|
||||
}
|
17
src/main/resources/static/images/redact-auto.svg
Normal file
17
src/main/resources/static/images/redact-auto.svg
Normal file
@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
|
||||
<symbol id="icon-redact-auto" viewBox="0 0 24 24"> <g id="Layer_2" data-name="Layer 2">
|
||||
<g id="Layer_1-2" data-name="Layer 1">
|
||||
<rect width="24" height="24" style="fill: none"/>
|
||||
<g>
|
||||
<path d="M17.541,15.64258a.91793.91793,0,0,1,.55469-.18555h1.1084a.91586.91586,0,0,1,.55469.18555,1.30889,1.30889,0,0,1,.40429.499,1.57206,1.57206,0,0,1,.15039.68457v5.47754H19.2041V20.21094H18.0957v2.09277H16.9873V16.82617a1.55843,1.55843,0,0,1,.15039-.68457A1.2979,1.2979,0,0,1,17.541,15.64258Zm1.66309,1.10547H18.0957v2.17187h1.1084Z" style="fill: currentColor"/>
|
||||
<path d="M5.68653,22.30351a2.00588,2.00588,0,0,1-2-2v-16A1.92585,1.92585,0,0,1,4.274,2.891a1.92585,1.92585,0,0,1,1.4125-.5875h8l6,6v5.66931h-2V9.30351h-5v-5h-7v16h9.74021v2Z" style="fill: currentColor"/>
|
||||
<rect x="7.69809" y="10.43189" width="4.33778" height="0.79501" style="fill: currentColor"/>
|
||||
<rect x="7.69809" y="12.16889" width="7.31192" height="1.21288" style="fill: currentColor"/>
|
||||
<rect x="7.69809" y="17.14555" width="7.31192" height="1.21288" style="fill: currentColor"/>
|
||||
<rect x="7.69809" y="14.32375" width="7.31192" height="0.57517" style="fill: currentColor"/>
|
||||
<rect x="7.69809" y="15.79848" width="5.25578" height="0.4475" style="fill: currentColor"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 1.4 KiB |
18
src/main/resources/static/images/redact-manual.svg
Normal file
18
src/main/resources/static/images/redact-manual.svg
Normal file
@ -0,0 +1,18 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
|
||||
<symbol id="icon-redact-manual" viewBox="-2 0 24 24">
|
||||
<g id="Layer_2" data-name="Layer 2">
|
||||
<g id="Layer_1-2" data-name="Layer 1">
|
||||
<rect width="24" height="24" style="fill: none"/>
|
||||
<g>
|
||||
<rect x="6.23853" y="10.43189" width="4.33778" height="0.79501" style="fill: currentColor"/>
|
||||
<rect x="6.23853" y="12.16889" width="7.31192" height="1.21288" style="fill: currentColor"/>
|
||||
<rect x="6.23853" y="17.14555" width="6.03324" height="1.21288" style="fill: currentColor"/>
|
||||
<rect x="6.23853" y="14.32375" width="7.31192" height="0.57517" style="fill: currentColor"/>
|
||||
<rect x="6.23853" y="15.79848" width="5.25578" height="0.4475" style="fill: currentColor"/>
|
||||
<path d="M12.5,22.30351v-3.075l5.525-5.5a1.36232,1.36232,0,0,1,.5-.325,1.59994,1.59994,0,0,1,.55-.1,1.49441,1.49441,0,0,1,1.075.45l.925.925a1.73875,1.73875,0,0,1,.3125.5,1.44287,1.44287,0,0,1,.1125.55,1.70613,1.70613,0,0,1-.1.5625,1.34171,1.34171,0,0,1-.325.5125l-5.5,5.5Zm7.5-6.575-.925-.925Zm-6,5.075h.95l3.025-3.05-.45-.475-.475-.45L14,19.85351Zm-9.5,1.5a1.9259,1.9259,0,0,1-1.4125-.5875A1.92586,1.92586,0,0,1,2.5,20.30351v-16A1.92585,1.92585,0,0,1,3.0875,2.891,1.92586,1.92586,0,0,1,4.5,2.30351h8l6,6v3h-2v-2h-5v-5h-7v16h6v2Zm13.025-5.025-.475-.45.925.925Z" style="fill: currentColor"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</symbol>
|
||||
</svg>
|
After Width: | Height: | Size: 1.4 KiB |
12
src/main/resources/static/images/split-auto.svg
Normal file
12
src/main/resources/static/images/split-auto.svg
Normal file
@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
|
||||
<symbol id="icon-split-auto" viewBox="0 0 24 24"> <g id="Layer_2" data-name="Layer 2"> <g id="Layer_2" data-name="Layer 2">
|
||||
<g id="Layer_1-2" data-name="Layer 1">
|
||||
<g>
|
||||
<path d="M18.42466,20.16555,12,13.74089,9.84315,15.89774a2.45776,2.45776,0,0,1,.2524.73425,4.481,4.481,0,0,1,.06883.78013A3.53515,3.53515,0,0,1,9.086,20.00493a3.53516,3.53516,0,0,1-2.59281,1.07843,3.53516,3.53516,0,0,1-2.59281-1.07843,3.6561,3.6561,0,0,1,0-5.18561,3.53516,3.53516,0,0,1,2.59281-1.07843,4.48117,4.48117,0,0,1,.78014.06884,2.45778,2.45778,0,0,1,.73424.25239l2.15685-2.15685L8.00753,9.74842a2.45752,2.45752,0,0,1-.73424.2524,4.48117,4.48117,0,0,1-.78014.06884A3.53516,3.53516,0,0,1,3.90034,8.99123,3.53515,3.53515,0,0,1,2.82192,6.39842,3.53515,3.53515,0,0,1,3.90034,3.80561,3.53515,3.53515,0,0,1,6.49315,2.72719,3.53515,3.53515,0,0,1,9.086,3.80561a3.53515,3.53515,0,0,1,1.07842,2.59281,4.48107,4.48107,0,0,1-.06883.78014,2.45786,2.45786,0,0,1-.2524.73425L21.17808,19.24774v.91781Zm-3.67123-9.17809L12.91781,9.15185,18.42466,3.645h2.75342v.91781ZM6.49315,8.234A1.841,1.841,0,0,0,8.32877,6.39842,1.841,1.841,0,0,0,6.49315,4.56281,1.841,1.841,0,0,0,4.65753,6.39842,1.841,1.841,0,0,0,6.49315,8.234ZM12,12.36418a.47051.47051,0,1,0-.32123-.13767A.44026.44026,0,0,0,12,12.36418ZM6.49315,19.24774a1.83562,1.83562,0,1,0-1.29641-3.132,1.83562,1.83562,0,0,0,1.29641,3.132Z" style="fill: currentColor"/>
|
||||
<path d="M18.0708,9.373a.73373.73373,0,0,1,.44434-.14942h.88867a.73372.73372,0,0,1,.44433.14942,1.04878,1.04878,0,0,1,.32374.40039,1.24521,1.24521,0,0,1,.1206.54883v4.3916h-.88867V13.03613h-.88867v1.67774h-.88868v-4.3916a1.24508,1.24508,0,0,1,.12061-.54883A1.04885,1.04885,0,0,1,18.0708,9.373Zm1.333.88672h-.88867V12h.88867Z" style="fill: currentColor" transform="translate(-5 -4) scale(1.3) "/>
|
||||
</g>
|
||||
<rect width="24" height="24" style="fill: none"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 2.0 KiB |
12
src/main/resources/static/images/split-chapters.svg
Normal file
12
src/main/resources/static/images/split-chapters.svg
Normal file
@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
|
||||
<symbol id="icon-split-chapters" viewBox="0 0 24 24"> <g id="Layer_2" data-name="Layer 2"> <g id="Layer_2" data-name="Layer 2">
|
||||
<g id="Layer_1-2" data-name="Layer 1">
|
||||
<g>
|
||||
<path d="M17.632,9.18527v5.44l1.94-1.16,1.94,1.16v-5.44Z" style="fill: currentColor"/>
|
||||
<path d="M18.09072,20.16555l-6.42466-6.42466L9.50921,15.89774a2.45775,2.45775,0,0,1,.25239.73425,4.481,4.481,0,0,1,.06884.78013A3.53516,3.53516,0,0,1,8.752,20.00493a3.53516,3.53516,0,0,1-2.5928,1.07843A3.53516,3.53516,0,0,1,3.5664,20.00493a3.65608,3.65608,0,0,1,0-5.18561,3.53516,3.53516,0,0,1,2.59281-1.07843,4.481,4.481,0,0,1,.78013.06884,2.45775,2.45775,0,0,1,.73425.25239l2.15685-2.15685L7.67359,9.74842a2.45749,2.45749,0,0,1-.73425.2524,4.481,4.481,0,0,1-.78013.06884A3.53516,3.53516,0,0,1,3.5664,8.99123,3.53516,3.53516,0,0,1,2.488,6.39842,3.53516,3.53516,0,0,1,3.5664,3.80561,3.53515,3.53515,0,0,1,6.15921,2.72719,3.53515,3.53515,0,0,1,8.752,3.80561,3.53516,3.53516,0,0,1,9.83044,6.39842a4.48109,4.48109,0,0,1-.06884.78014,2.45784,2.45784,0,0,1-.25239.73425L20.84414,19.24774v.91781Zm-3.67124-9.17809L12.58386,9.15185,18.09072,3.645h2.75342v.91781ZM6.15921,8.234A1.841,1.841,0,0,0,7.99482,6.39842,1.841,1.841,0,0,0,6.15921,4.56281,1.841,1.841,0,0,0,4.32359,6.39842,1.841,1.841,0,0,0,6.15921,8.234Zm5.50685,4.13014a.47051.47051,0,1,0-.32124-.13767A.44026.44026,0,0,0,11.66606,12.36418ZM6.15921,19.24774a1.83562,1.83562,0,1,0-1.29641-3.132,1.83562,1.83562,0,0,0,1.29641,3.132Z" style="fill: currentColor"/>
|
||||
</g>
|
||||
<rect width="24" height="24" style="fill: none"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 1.7 KiB |
16
src/main/resources/static/images/split-size.svg
Normal file
16
src/main/resources/static/images/split-size.svg
Normal file
@ -0,0 +1,16 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" style="padding-left: 20px; margin-right: -20px;">
|
||||
<symbol id="icon-split-size" viewBox="0 0 24 24"> <g id="Layer_2" data-name="Layer 2"> <g id="Layer_2" data-name="Layer 2">
|
||||
<g id="Layer_1-2" data-name="Layer 1">
|
||||
<g>
|
||||
<path d="M17.90313,20.16555l-6.42466-6.42466L9.32162,15.89774a2.45776,2.45776,0,0,1,.2524.73425,4.481,4.481,0,0,1,.06883.78013,3.53515,3.53515,0,0,1-1.07842,2.59281,3.53516,3.53516,0,0,1-2.59281,1.07843,3.53516,3.53516,0,0,1-2.59281-1.07843,3.6561,3.6561,0,0,1,0-5.18561,3.53516,3.53516,0,0,1,2.59281-1.07843,4.48117,4.48117,0,0,1,.78014.06884,2.45778,2.45778,0,0,1,.73424.25239l2.15685-2.15685L7.486,9.74842a2.45752,2.45752,0,0,1-.73424.2524,4.48117,4.48117,0,0,1-.78014.06884A3.53516,3.53516,0,0,1,3.37881,8.99123,3.53515,3.53515,0,0,1,2.30039,6.39842,3.53515,3.53515,0,0,1,3.37881,3.80561,3.53515,3.53515,0,0,1,5.97162,2.72719,3.53515,3.53515,0,0,1,8.56443,3.80561,3.53515,3.53515,0,0,1,9.64285,6.39842a4.48107,4.48107,0,0,1-.06883.78014,2.45786,2.45786,0,0,1-.2524.73425L20.65655,19.24774v.91781Zm-3.67124-9.17809L12.39628,9.15185,17.90313,3.645h2.75342v.91781ZM5.97162,8.234A1.841,1.841,0,0,0,7.80724,6.39842,1.841,1.841,0,0,0,5.97162,4.56281,1.841,1.841,0,0,0,4.136,6.39842,1.841,1.841,0,0,0,5.97162,8.234Zm5.50685,4.13014a.47051.47051,0,1,0-.32123-.13767A.44026.44026,0,0,0,11.47847,12.36418ZM5.97162,19.24774a1.83562,1.83562,0,1,0-1.29641-3.132,1.83562,1.83562,0,0,0,1.29641,3.132Z" style="fill: currentColor"/>
|
||||
<g>
|
||||
<rect x="18.32071" y="7.9834" width="3.37891" height="2" style="fill: currentColor"/>
|
||||
<rect x="18.32071" y="10.90527" width="3.37891" height="2" style="fill: currentColor"/>
|
||||
<rect x="18.32071" y="13.82715" width="3.37891" height="2" style="fill: currentColor"/>
|
||||
</g>
|
||||
</g>
|
||||
<rect width="24" height="24" style="fill: none"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 1.9 KiB |
@ -1,53 +1,65 @@
|
||||
function updateFavoritesDropdown() {
|
||||
var dropdown = document.querySelector("#favoritesDropdown");
|
||||
|
||||
if (!dropdown) {
|
||||
console.error('Dropdown element with ID "favoritesDropdown" not found!');
|
||||
return;
|
||||
}
|
||||
dropdown.innerHTML = "";
|
||||
|
||||
var hasFavorites = false;
|
||||
var addedFeatures = new Set();
|
||||
const favoritesList = JSON.parse(localStorage.getItem('favoritesList')) || [];
|
||||
|
||||
for (var i = 0; i < localStorage.length; i++) {
|
||||
var key = localStorage.key(i);
|
||||
var value = localStorage.getItem(key);
|
||||
|
||||
if (value === "favorite") {
|
||||
var navbarEntry = document.querySelector(`a[href='${key}']`);
|
||||
if (value === 'favorite') {
|
||||
const index = favoritesList.indexOf(key);
|
||||
if (index === -1) {
|
||||
favoritesList.push(key);
|
||||
localStorage.removeItem(key);
|
||||
console.log(`Added to favorites: ${key}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var dropdown = document.querySelector('#favoritesDropdown');
|
||||
|
||||
if (!dropdown) {
|
||||
console.error('Dropdown element with ID "favoritesDropdown" not found!');
|
||||
return;
|
||||
}
|
||||
dropdown.innerHTML = '';
|
||||
|
||||
var hasFavorites = false;
|
||||
var addedFeatures = new Set();
|
||||
|
||||
for (var i = 0; i < favoritesList.length; i++) {
|
||||
var value = favoritesList[i];
|
||||
if (value) {
|
||||
var navbarEntry = document.querySelector(`a[data-bs-link='${value}']`);
|
||||
if (navbarEntry) {
|
||||
var featureName = navbarEntry.textContent.trim();
|
||||
|
||||
if (!addedFeatures.has(featureName)) {
|
||||
var dropdownItem = document.createElement("div");
|
||||
dropdownItem.className = "dropdown-item d-flex justify-content-between align-items-center";
|
||||
var dropdownItem = document.createElement('div');
|
||||
dropdownItem.className = 'dropdown-item d-flex justify-content-between align-items-center';
|
||||
|
||||
// Create a wrapper for the original content
|
||||
var contentWrapper = document.createElement("div");
|
||||
contentWrapper.className = "d-flex align-items-center flex-grow-1";
|
||||
contentWrapper.style.textDecoration = "none";
|
||||
contentWrapper.style.color = "inherit";
|
||||
var contentWrapper = document.createElement('div');
|
||||
contentWrapper.className = 'd-flex align-items-center flex-grow-1';
|
||||
contentWrapper.style.textDecoration = 'none';
|
||||
contentWrapper.style.color = 'inherit';
|
||||
|
||||
// Clone the original content
|
||||
var originalContent = navbarEntry.querySelector('div').cloneNode(true);
|
||||
contentWrapper.appendChild(originalContent);
|
||||
|
||||
// Create the remove button
|
||||
var removeButton = document.createElement("button");
|
||||
removeButton.className = "btn btn-sm btn-link p-0 ml-2";
|
||||
var removeButton = document.createElement('button');
|
||||
removeButton.className = 'btn btn-sm btn-link p-0 ml-2';
|
||||
removeButton.innerHTML = '<i class="material-symbols-rounded close-icon" style="font-size: 18px;">close</i>';
|
||||
removeButton.onclick = function(itemKey, event) {
|
||||
removeButton.onclick = function (itemKey, event) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
localStorage.removeItem(itemKey);
|
||||
updateFavoritesSection();
|
||||
addToFavorites(itemKey);
|
||||
updateFavoritesDropdown();
|
||||
filterCards();
|
||||
}.bind(null, key);
|
||||
}.bind(null, value);
|
||||
|
||||
// Add click event to the content wrapper
|
||||
contentWrapper.onclick = function(itemHref, event) {
|
||||
contentWrapper.onclick = function (itemHref, event) {
|
||||
event.preventDefault();
|
||||
window.location.href = itemHref;
|
||||
}.bind(null, navbarEntry.href);
|
||||
@ -58,16 +70,67 @@ function updateFavoritesDropdown() {
|
||||
hasFavorites = true;
|
||||
addedFeatures.add(featureName);
|
||||
}
|
||||
} else {
|
||||
console.warn(`Navbar entry not found for key: ${key}`);
|
||||
}
|
||||
} else {
|
||||
console.warn(`Navbar entry not found for : ${value}`);
|
||||
}
|
||||
}
|
||||
|
||||
if (!hasFavorites) {
|
||||
var defaultItem = document.createElement("a");
|
||||
defaultItem.className = "dropdown-item";
|
||||
defaultItem.textContent = noFavourites || "No favorites added";
|
||||
var defaultItem = document.createElement('a');
|
||||
defaultItem.className = 'dropdown-item';
|
||||
defaultItem.textContent = noFavourites || 'No favorites added';
|
||||
dropdown.appendChild(defaultItem);
|
||||
}
|
||||
}
|
||||
|
||||
function updateFavoriteIcons() {
|
||||
const favoritesList = JSON.parse(localStorage.getItem('favoritesList')) || [];
|
||||
|
||||
// Select all favorite icons
|
||||
document.querySelectorAll('.favorite-icon').forEach((icon) => {
|
||||
const endpoint = icon.getAttribute('data-endpoint');
|
||||
const parent = icon.closest('.dropdown-item');
|
||||
|
||||
// Determine if the icon belongs to groupRecent or groupFavorites
|
||||
const isInGroupRecent = parent?.closest('#groupRecent') !== null;
|
||||
const isInGroupFavorites = parent?.closest('#groupFavorites') !== null;
|
||||
|
||||
if (isInGroupRecent) {
|
||||
icon.style.display = 'none';
|
||||
} else if (isInGroupFavorites) {
|
||||
icon.textContent = 'close_small';
|
||||
icon.style.color = 'palevioletred';
|
||||
} else {
|
||||
icon.textContent = favoritesList.includes(endpoint) ? 'close_small' : 'add';
|
||||
icon.className = favoritesList.includes(endpoint)
|
||||
? 'material-symbols-rounded favorite-icon close-icon'
|
||||
: 'material-symbols-rounded favorite-icon add-icon';
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function addToFavorites(entryId) {
|
||||
if (entryId) {
|
||||
const favoritesList = JSON.parse(localStorage.getItem('favoritesList')) || [];
|
||||
const index = favoritesList.indexOf(entryId);
|
||||
|
||||
if (index === -1) {
|
||||
favoritesList.push(entryId);
|
||||
console.log(`Added to favorites: ${entryId}`);
|
||||
} else {
|
||||
favoritesList.splice(index, 1);
|
||||
console.log(`Removed from favorites: ${entryId}`);
|
||||
}
|
||||
|
||||
localStorage.setItem('favoritesList', JSON.stringify(favoritesList));
|
||||
updateFavoritesDropdown();
|
||||
updateFavoriteIcons();
|
||||
const currentPath = window.location.pathname;
|
||||
if (currentPath.includes('home-legacy')) {
|
||||
syncFavoritesLegacy();
|
||||
} else {
|
||||
initializeCards();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
259
src/main/resources/static/js/homecard-legacy.js
Normal file
259
src/main/resources/static/js/homecard-legacy.js
Normal file
@ -0,0 +1,259 @@
|
||||
function filterCardsLegacy() {
|
||||
var input = document.getElementById('searchBar');
|
||||
var filter = input.value.toUpperCase();
|
||||
|
||||
let featureGroups = document.querySelectorAll('.feature-group-legacy');
|
||||
const collapsedGroups = getCollapsedGroups();
|
||||
|
||||
for (const featureGroup of featureGroups) {
|
||||
var cards = featureGroup.querySelectorAll('.feature-card');
|
||||
|
||||
let groupMatchesFilter = false;
|
||||
for (var i = 0; i < cards.length; i++) {
|
||||
var card = cards[i];
|
||||
var title = card.querySelector('h5.card-title').innerText;
|
||||
var text = card.querySelector('p.card-text').innerText;
|
||||
|
||||
// Get the navbar tags associated with the card
|
||||
var navbarItem = document.querySelector(`a.dropdown-item[href="${card.id}"]`);
|
||||
var navbarTags = navbarItem ? navbarItem.getAttribute('data-bs-tags') : '';
|
||||
|
||||
var content = title + ' ' + text + ' ' + navbarTags;
|
||||
|
||||
if (content.toUpperCase().indexOf(filter) > -1) {
|
||||
card.style.display = '';
|
||||
groupMatchesFilter = true;
|
||||
} else {
|
||||
card.style.display = 'none';
|
||||
}
|
||||
}
|
||||
|
||||
if (!groupMatchesFilter) {
|
||||
featureGroup.style.display = 'none';
|
||||
} else {
|
||||
featureGroup.style.display = '';
|
||||
resetOrTemporarilyExpandGroup(featureGroup, filter, collapsedGroups);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getCollapsedGroups() {
|
||||
return localStorage.getItem('collapsedGroups') ? JSON.parse(localStorage.getItem('collapsedGroups')) : [];
|
||||
}
|
||||
|
||||
function resetOrTemporarilyExpandGroup(featureGroup, filterKeywords = '', collapsedGroups = []) {
|
||||
const shouldResetCollapse = filterKeywords.trim() === '';
|
||||
if (shouldResetCollapse) {
|
||||
// Resetting the group's expand/collapse to its original state (as in collapsed groups)
|
||||
const isCollapsed = collapsedGroups.indexOf(featureGroup.id) != -1;
|
||||
expandCollapseToggle(featureGroup, !isCollapsed);
|
||||
} else {
|
||||
// Temporarily expands feature group without affecting the actual/stored collapsed groups
|
||||
featureGroup.classList.remove('collapsed');
|
||||
featureGroup.querySelector('.header-expand-button').classList.remove('collapsed');
|
||||
}
|
||||
}
|
||||
|
||||
function updateFavoritesSectionLegacy() {
|
||||
const favoritesContainer = document.getElementById('groupFavorites').querySelector('.feature-group-container');
|
||||
favoritesContainer.innerHTML = '';
|
||||
const cards = Array.from(document.querySelectorAll('.feature-card:not(.duplicate)'));
|
||||
const addedCardIds = new Set();
|
||||
let favoritesAmount = 0;
|
||||
|
||||
cards.forEach((card) => {
|
||||
const favouritesList = JSON.parse(localStorage.getItem('favoritesList') || '[]');
|
||||
|
||||
if (favouritesList.includes(card.id) && !addedCardIds.has(card.id)) {
|
||||
const duplicate = card.cloneNode(true);
|
||||
duplicate.classList.add('duplicate');
|
||||
favoritesContainer.appendChild(duplicate);
|
||||
addedCardIds.add(card.id);
|
||||
favoritesAmount++;
|
||||
}
|
||||
});
|
||||
|
||||
if (favoritesAmount === 0) {
|
||||
document.getElementById('groupFavorites').style.display = 'none';
|
||||
} else {
|
||||
document.getElementById('groupFavorites').style.display = 'flex';
|
||||
}
|
||||
reorderCards(favoritesContainer);
|
||||
}
|
||||
|
||||
function syncFavoritesLegacy() {
|
||||
const cards = Array.from(document.querySelectorAll('.feature-card'));
|
||||
cards.forEach((card) => {
|
||||
const isFavorite = localStorage.getItem(card.id) === 'favorite';
|
||||
const starIcon = card.querySelector('.favorite-icon span.material-symbols-rounded');
|
||||
if (starIcon) {
|
||||
if (isFavorite) {
|
||||
starIcon.classList.remove('no-fill');
|
||||
starIcon.classList.add('fill');
|
||||
card.classList.add('favorite');
|
||||
} else {
|
||||
starIcon.classList.remove('fill');
|
||||
starIcon.classList.add('no-fill');
|
||||
card.classList.remove('favorite');
|
||||
}
|
||||
}
|
||||
});
|
||||
updateFavoritesSectionLegacy();
|
||||
updateFavoritesDropdown();
|
||||
filterCardsLegacy();
|
||||
}
|
||||
|
||||
function reorderCards(container) {
|
||||
var cards = Array.from(container.querySelectorAll('.feature-card'));
|
||||
cards.forEach(function (card) {
|
||||
container.removeChild(card);
|
||||
});
|
||||
cards.sort(function (a, b) {
|
||||
var aIsFavorite = localStorage.getItem(a.id) === 'favorite';
|
||||
var bIsFavorite = localStorage.getItem(b.id) === 'favorite';
|
||||
if (a.id === 'update-link') {
|
||||
return -1;
|
||||
}
|
||||
if (b.id === 'update-link') {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (aIsFavorite && !bIsFavorite) {
|
||||
return -1;
|
||||
} else if (!aIsFavorite && bIsFavorite) {
|
||||
return 1;
|
||||
} else {
|
||||
return a.id > b.id;
|
||||
}
|
||||
});
|
||||
cards.forEach(function (card) {
|
||||
container.appendChild(card);
|
||||
});
|
||||
}
|
||||
|
||||
function reorderAllCards() {
|
||||
const containers = Array.from(document.querySelectorAll('.feature-group-container'));
|
||||
containers.forEach(function (container) {
|
||||
reorderCards(container);
|
||||
});
|
||||
}
|
||||
|
||||
function initializeCardsLegacy() {
|
||||
reorderAllCards();
|
||||
updateFavoritesSectionLegacy();
|
||||
updateFavoritesDropdown();
|
||||
filterCardsLegacy();
|
||||
}
|
||||
|
||||
function showFavoritesOnly() {
|
||||
const groups = Array.from(document.querySelectorAll('.feature-group-legacy'));
|
||||
if (localStorage.getItem('favoritesOnly') === 'true') {
|
||||
groups.forEach((group) => {
|
||||
if (group.id !== 'groupFavorites') {
|
||||
group.style.display = 'none';
|
||||
}
|
||||
});
|
||||
} else {
|
||||
groups.forEach((group) => {
|
||||
if (group.id !== 'groupFavorites') {
|
||||
group.style.display = 'flex';
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function toggleFavoritesOnly() {
|
||||
if (localStorage.getItem('favoritesOnly') === 'true') {
|
||||
localStorage.setItem('favoritesOnly', 'false');
|
||||
} else {
|
||||
localStorage.setItem('favoritesOnly', 'true');
|
||||
}
|
||||
showFavoritesOnly();
|
||||
}
|
||||
|
||||
// Expands a feature group on true, collapses it on false and toggles state on null.
|
||||
function expandCollapseToggle(group, expand = null) {
|
||||
if (expand === null) {
|
||||
group.classList.toggle('collapsed');
|
||||
group.querySelector('.header-expand-button').classList.toggle('collapsed');
|
||||
} else if (expand) {
|
||||
group.classList.remove('collapsed');
|
||||
group.querySelector('.header-expand-button').classList.remove('collapsed');
|
||||
} else {
|
||||
group.classList.add('collapsed');
|
||||
group.querySelector('.header-expand-button').classList.add('collapsed');
|
||||
}
|
||||
|
||||
const collapsed = localStorage.getItem('collapsedGroups') ? JSON.parse(localStorage.getItem('collapsedGroups')) : [];
|
||||
const groupIndex = collapsed.indexOf(group.id);
|
||||
|
||||
if (group.classList.contains('collapsed')) {
|
||||
if (groupIndex === -1) {
|
||||
collapsed.push(group.id);
|
||||
}
|
||||
} else {
|
||||
if (groupIndex !== -1) {
|
||||
collapsed.splice(groupIndex, 1);
|
||||
}
|
||||
}
|
||||
|
||||
localStorage.setItem('collapsedGroups', JSON.stringify(collapsed));
|
||||
}
|
||||
|
||||
function expandCollapseAll(expandAll) {
|
||||
const groups = Array.from(document.querySelectorAll('.feature-group-legacy'));
|
||||
groups.forEach((group) => {
|
||||
expandCollapseToggle(group, expandAll);
|
||||
});
|
||||
}
|
||||
|
||||
window.onload = function () {
|
||||
initializeCardsLegacy();
|
||||
syncFavoritesLegacy(); // Ensure everything is in sync on page load
|
||||
};
|
||||
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
const materialIcons = new FontFaceObserver('Material Symbols Rounded');
|
||||
|
||||
materialIcons
|
||||
.load()
|
||||
.then(() => {
|
||||
document.querySelectorAll('.feature-card.hidden').forEach((el) => {
|
||||
el.classList.remove('hidden');
|
||||
});
|
||||
})
|
||||
.catch(() => {
|
||||
console.error('Material Symbols Rounded font failed to load.');
|
||||
});
|
||||
|
||||
Array.from(document.querySelectorAll('.feature-group-header-legacy')).forEach((header) => {
|
||||
const parent = header.parentNode;
|
||||
const container = header.parentNode.querySelector('.feature-group-container');
|
||||
if (parent.id !== 'groupFavorites') {
|
||||
// container.style.maxHeight = container.scrollHeight + 'px';
|
||||
}
|
||||
header.onclick = () => {
|
||||
expandCollapseToggle(parent);
|
||||
};
|
||||
});
|
||||
|
||||
const collapsed = localStorage.getItem('collapsedGroups') ? JSON.parse(localStorage.getItem('collapsedGroups')) : [];
|
||||
const groupsArray = Array.from(document.querySelectorAll('.feature-group-legacy'));
|
||||
|
||||
groupsArray.forEach((group) => {
|
||||
if (collapsed.indexOf(group.id) !== -1) {
|
||||
expandCollapseToggle(group, false);
|
||||
}
|
||||
});
|
||||
|
||||
// Necessary in order to not fire the transition animation on page load, which looks wrong.
|
||||
// The timeout isn't doing anything visible to the user, so it's not making the page load look slower.
|
||||
setTimeout(() => {
|
||||
groupsArray.forEach((group) => {
|
||||
const container = group.querySelector('.feature-group-container');
|
||||
container.classList.add('animated-group');
|
||||
});
|
||||
}, 500);
|
||||
|
||||
showFavoritesOnly();
|
||||
});
|
@ -1,159 +1,90 @@
|
||||
function filterCards() {
|
||||
var input = document.getElementById("searchBar");
|
||||
var filter = input.value.toUpperCase();
|
||||
var input = document.getElementById('searchBar');
|
||||
var filter = input.value.toUpperCase().trim();
|
||||
|
||||
let featureGroups = document.querySelectorAll(".feature-group");
|
||||
const collapsedGroups = getCollapsedGroups();
|
||||
// Split the input filter into individual words for multi-word matching
|
||||
var filterWords = filter.split(/[\s,;.\-]+/);
|
||||
|
||||
let featureGroups = document.querySelectorAll('.feature-group');
|
||||
for (const featureGroup of featureGroups) {
|
||||
var cards = featureGroup.querySelectorAll(".feature-card");
|
||||
var cards = featureGroup.querySelectorAll('.dropdown-item');
|
||||
|
||||
let groupMatchesFilter = false;
|
||||
for (var i = 0; i < cards.length; i++) {
|
||||
var card = cards[i];
|
||||
var title = card.querySelector("h5.card-title").innerText;
|
||||
var text = card.querySelector("p.card-text").innerText;
|
||||
var title = card.getAttribute('title') || '';
|
||||
|
||||
// Get the navbar tags associated with the card
|
||||
var navbarItem = document.querySelector(`a.dropdown-item[href="${card.id}"]`);
|
||||
var navbarTags = navbarItem ? navbarItem.getAttribute("data-bs-tags") : "";
|
||||
var navbarTags = navbarItem ? navbarItem.getAttribute('data-bs-tags') : '';
|
||||
var navbarTags = navbarItem ? navbarTags + ',' + navbarItem.getAttribute('data-bs-title') : '';
|
||||
|
||||
var content = title + " " + text + " " + navbarTags;
|
||||
var content = (title + ' ' + navbarTags).toUpperCase();
|
||||
|
||||
if (content.toUpperCase().indexOf(filter) > -1) {
|
||||
card.style.display = "";
|
||||
// Check if all words in the filter match the content
|
||||
var matches = filterWords.every((word) => content.includes(word));
|
||||
|
||||
if (matches) {
|
||||
card.style.display = '';
|
||||
groupMatchesFilter = true;
|
||||
} else {
|
||||
card.style.display = "none";
|
||||
card.style.display = 'none';
|
||||
}
|
||||
}
|
||||
|
||||
if (!groupMatchesFilter) {
|
||||
featureGroup.style.display = "none";
|
||||
featureGroup.style.display = 'none';
|
||||
} else {
|
||||
featureGroup.style.display = "";
|
||||
resetOrTemporarilyExpandGroup(featureGroup, filter, collapsedGroups);
|
||||
featureGroup.style.display = '';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getCollapsedGroups() {
|
||||
return localStorage.getItem("collapsedGroups") ? JSON.parse(localStorage.getItem("collapsedGroups")) : [];
|
||||
}
|
||||
|
||||
function resetOrTemporarilyExpandGroup(featureGroup, filterKeywords = "", collapsedGroups = []) {
|
||||
const shouldResetCollapse = filterKeywords.trim() === "";
|
||||
if (shouldResetCollapse) {
|
||||
// Resetting the group's expand/collapse to its original state (as in collapsed groups)
|
||||
const isCollapsed = collapsedGroups.indexOf(featureGroup.id) != -1;
|
||||
expandCollapseToggle(featureGroup, !isCollapsed);
|
||||
} else {
|
||||
// Temporarily expands feature group without affecting the actual/stored collapsed groups
|
||||
featureGroup.classList.remove("collapsed");
|
||||
featureGroup.querySelector(".header-expand-button").classList.remove("collapsed");
|
||||
}
|
||||
}
|
||||
|
||||
function updateFavoritesSection() {
|
||||
const favoritesContainer = document.getElementById("groupFavorites").querySelector(".feature-group-container");
|
||||
favoritesContainer.style.maxHeight = "none";
|
||||
favoritesContainer.innerHTML = ""; // Clear the container first
|
||||
const cards = Array.from(document.querySelectorAll(".feature-card:not(.duplicate)"));
|
||||
const addedCardIds = new Set(); // To keep track of added card IDs
|
||||
const favoritesContainer = document.getElementById('groupFavorites').querySelector('.nav-group-container');
|
||||
favoritesContainer.innerHTML = '';
|
||||
let favoritesAmount = 0;
|
||||
const favouritesList = JSON.parse(localStorage.getItem('favoritesList') || '[]');
|
||||
const isFavoritesView = JSON.parse(localStorage.getItem('favoritesView') || 'false');
|
||||
|
||||
cards.forEach(card => {
|
||||
if (localStorage.getItem(card.id) === "favorite" && !addedCardIds.has(card.id)) {
|
||||
const duplicate = card.cloneNode(true);
|
||||
duplicate.classList.add("duplicate");
|
||||
favouritesList.forEach((value) => {
|
||||
var navbarEntry = document.querySelector(`a[data-bs-link='${value}']`);
|
||||
if (navbarEntry) {
|
||||
const duplicate = navbarEntry.cloneNode(true);
|
||||
favoritesContainer.appendChild(duplicate);
|
||||
addedCardIds.add(card.id); // Mark this card as added
|
||||
favoritesAmount++;
|
||||
}
|
||||
favoritesAmount++;
|
||||
});
|
||||
|
||||
if (favoritesAmount === 0) {
|
||||
document.getElementById("groupFavorites").style.display = "none";
|
||||
if (favoritesAmount === 0 || !isFavoritesView) {
|
||||
document.getElementById('groupFavorites').style.display = 'none';
|
||||
} else {
|
||||
document.getElementById("groupFavorites").style.display = "flex";
|
||||
document.getElementById('groupFavorites').style.display = 'flex';
|
||||
}
|
||||
reorderCards(favoritesContainer);
|
||||
favoritesContainer.style.maxHeight = favoritesContainer.scrollHeight + "px";
|
||||
}
|
||||
|
||||
function toggleFavorite(element) {
|
||||
var span = element.querySelector("span.material-symbols-rounded");
|
||||
var card = element.closest(".feature-card");
|
||||
var cardId = card.id;
|
||||
|
||||
// Prevent the event from bubbling up to parent elements
|
||||
event.stopPropagation();
|
||||
|
||||
if (span.classList.contains("no-fill")) {
|
||||
span.classList.remove("no-fill");
|
||||
span.classList.add("fill");
|
||||
card.classList.add("favorite");
|
||||
localStorage.setItem(cardId, "favorite");
|
||||
} else {
|
||||
span.classList.remove("fill");
|
||||
span.classList.add("no-fill");
|
||||
card.classList.remove("favorite");
|
||||
localStorage.removeItem(cardId);
|
||||
}
|
||||
|
||||
// Use setTimeout to ensure this runs after the current call stack is clear
|
||||
setTimeout(() => {
|
||||
reorderCards(card.parentNode);
|
||||
updateFavoritesSection();
|
||||
updateFavoritesDropdown();
|
||||
filterCards();
|
||||
}, 0);
|
||||
}
|
||||
|
||||
function syncFavorites() {
|
||||
const cards = Array.from(document.querySelectorAll(".feature-card"));
|
||||
cards.forEach(card => {
|
||||
const isFavorite = localStorage.getItem(card.id) === "favorite";
|
||||
const starIcon = card.querySelector(".favorite-icon span.material-symbols-rounded");
|
||||
if (starIcon) {
|
||||
if (isFavorite) {
|
||||
starIcon.classList.remove("no-fill");
|
||||
starIcon.classList.add("fill");
|
||||
card.classList.add("favorite");
|
||||
} else {
|
||||
starIcon.classList.remove("fill");
|
||||
starIcon.classList.add("no-fill");
|
||||
card.classList.remove("favorite");
|
||||
}
|
||||
}
|
||||
});
|
||||
updateFavoritesSection();
|
||||
updateFavoritesDropdown();
|
||||
filterCards();
|
||||
//favoritesContainer.style.maxHeight = favoritesContainer.scrollHeight + 'px';
|
||||
}
|
||||
|
||||
function reorderCards(container) {
|
||||
var cards = Array.from(container.querySelectorAll(".feature-card"));
|
||||
var cards = Array.from(container.querySelectorAll('.dropdown-item'));
|
||||
cards.forEach(function (card) {
|
||||
container.removeChild(card);
|
||||
});
|
||||
cards.sort(function (a, b) {
|
||||
var aIsFavorite = localStorage.getItem(a.id) === "favorite";
|
||||
var bIsFavorite = localStorage.getItem(b.id) === "favorite";
|
||||
if (a.id === "update-link") {
|
||||
var aIsFavorite = localStorage.getItem(a.id) === 'favorite';
|
||||
var bIsFavorite = localStorage.getItem(b.id) === 'favorite';
|
||||
if (a.id === 'update-link') {
|
||||
return -1;
|
||||
}
|
||||
if (b.id === "update-link") {
|
||||
if (b.id === 'update-link') {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (aIsFavorite && !bIsFavorite) {
|
||||
return -1;
|
||||
}
|
||||
else if (!aIsFavorite && bIsFavorite) {
|
||||
} else if (!aIsFavorite && bIsFavorite) {
|
||||
return 1;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
return a.id > b.id;
|
||||
}
|
||||
});
|
||||
@ -162,136 +93,165 @@ function reorderCards(container) {
|
||||
});
|
||||
}
|
||||
|
||||
function reorderAllCards() {
|
||||
const containers = Array.from(document.querySelectorAll(".feature-group-container"));
|
||||
containers.forEach(function (container) {
|
||||
reorderCards(container);
|
||||
})
|
||||
}
|
||||
|
||||
function initializeCards() {
|
||||
var cards = document.querySelectorAll(".feature-card");
|
||||
cards.forEach(function (card) {
|
||||
var cardId = card.id;
|
||||
var span = card.querySelector(".favorite-icon span.material-symbols-rounded");
|
||||
if (localStorage.getItem(cardId) === "favorite") {
|
||||
span.classList.remove("no-fill");
|
||||
span.classList.add("fill");
|
||||
card.classList.add("favorite");
|
||||
}
|
||||
});
|
||||
reorderAllCards();
|
||||
updateFavoritesSection();
|
||||
updateFavoritesDropdown();
|
||||
filterCards();
|
||||
}
|
||||
|
||||
function showFavoritesOnly() {
|
||||
const groups = Array.from(document.querySelectorAll(".feature-group"));
|
||||
if (localStorage.getItem("favoritesOnly") === "true") {
|
||||
groups.forEach((group) => {
|
||||
if (group.id !== "groupFavorites") {
|
||||
group.style.display = "none";
|
||||
};
|
||||
})
|
||||
} else {
|
||||
groups.forEach((group) => {
|
||||
if (group.id !== "groupFavorites") {
|
||||
group.style.display = "flex";
|
||||
};
|
||||
})
|
||||
};
|
||||
}
|
||||
function updateFavoritesView() {
|
||||
const isFavoritesView = JSON.parse(localStorage.getItem('favoritesView') || 'false');
|
||||
const textElement = document.getElementById('toggle-favourites-text');
|
||||
const iconElement = document.getElementById('toggle-favourites-icon');
|
||||
const favoritesGroup = document.querySelector('#groupFavorites');
|
||||
const favoritesList = JSON.parse(localStorage.getItem('favoritesList')) || [];
|
||||
document.getElementById('favouritesVisibility').style.display = 'flex';
|
||||
|
||||
function toggleFavoritesOnly() {
|
||||
if (localStorage.getItem("favoritesOnly") === "true") {
|
||||
localStorage.setItem("favoritesOnly", "false");
|
||||
if (isFavoritesView && favoritesList.length > 0) {
|
||||
iconElement.textContent = 'visibility_off';
|
||||
favoritesGroup.style.display = 'flex';
|
||||
} else {
|
||||
localStorage.setItem("favoritesOnly", "true");
|
||||
}
|
||||
showFavoritesOnly();
|
||||
}
|
||||
|
||||
// Expands a feature group on true, collapses it on false and toggles state on null.
|
||||
function expandCollapseToggle(group, expand = null) {
|
||||
if (expand === null) {
|
||||
group.classList.toggle("collapsed");
|
||||
group.querySelector(".header-expand-button").classList.toggle("collapsed");
|
||||
} else if (expand) {
|
||||
group.classList.remove("collapsed");
|
||||
group.querySelector(".header-expand-button").classList.remove("collapsed");
|
||||
} else {
|
||||
group.classList.add("collapsed");
|
||||
group.querySelector(".header-expand-button").classList.add("collapsed");
|
||||
}
|
||||
|
||||
const collapsed = localStorage.getItem("collapsedGroups") ? JSON.parse(localStorage.getItem("collapsedGroups")) : [];
|
||||
const groupIndex = collapsed.indexOf(group.id);
|
||||
|
||||
if (group.classList.contains("collapsed")) {
|
||||
if (groupIndex === -1) {
|
||||
collapsed.push(group.id);
|
||||
}
|
||||
} else {
|
||||
if (groupIndex !== -1) {
|
||||
collapsed.splice(groupIndex, 1);
|
||||
if (favoritesList.length > 0) {
|
||||
iconElement.textContent = 'visibility';
|
||||
favoritesGroup.style.display = 'none';
|
||||
} else {
|
||||
document.getElementById('favouritesVisibility').style.display = 'none';
|
||||
}
|
||||
}
|
||||
|
||||
localStorage.setItem("collapsedGroups", JSON.stringify(collapsed));
|
||||
}
|
||||
|
||||
function expandCollapseAll(expandAll) {
|
||||
const groups = Array.from(document.querySelectorAll(".feature-group"));
|
||||
groups.forEach((group) => {
|
||||
expandCollapseToggle(group, expandAll);
|
||||
})
|
||||
}
|
||||
function toggleFavoritesMode() {
|
||||
const favoritesMode = !document.querySelector('.toggle-favourites').classList.contains('active');
|
||||
document.querySelector('.toggle-favourites').classList.toggle('active', favoritesMode);
|
||||
|
||||
window.onload = function() {
|
||||
initializeCards();
|
||||
syncFavorites(); // Ensure everything is in sync on page load
|
||||
};
|
||||
document.querySelectorAll('.favorite-icon').forEach((icon) => {
|
||||
const endpoint = icon.getAttribute('data-endpoint');
|
||||
const parent = icon.closest('.dropdown-item');
|
||||
const isInGroupRecent = parent.closest('#groupRecent') !== null;
|
||||
const isInGroupFavorites = parent.closest('#groupFavorites') !== null;
|
||||
|
||||
document.addEventListener("DOMContentLoaded", function () {
|
||||
const materialIcons = new FontFaceObserver('Material Symbols Rounded');
|
||||
if (isInGroupRecent) {
|
||||
icon.style.display = 'none';
|
||||
} else if (isInGroupFavorites) {
|
||||
icon.style.display = favoritesMode ? 'inline-block' : 'none';
|
||||
icon.textContent = 'close_small';
|
||||
} else {
|
||||
icon.style.display = favoritesMode ? 'inline-block' : 'none';
|
||||
|
||||
materialIcons.load().then(() => {
|
||||
document.querySelectorAll('.feature-card.hidden').forEach(el => {
|
||||
el.classList.remove('hidden');
|
||||
});
|
||||
}).catch(() => {
|
||||
console.error('Material Symbols Rounded font failed to load.');
|
||||
const favoritesList = JSON.parse(localStorage.getItem('favoritesList')) || [];
|
||||
icon.textContent = favoritesList.includes(endpoint) ? 'close_small' : 'add';
|
||||
}
|
||||
});
|
||||
|
||||
Array.from(document.querySelectorAll(".feature-group-header")).forEach(header => {
|
||||
const parent = header.parentNode;
|
||||
const container = header.parentNode.querySelector(".feature-group-container");
|
||||
if (parent.id !== "groupFavorites") {
|
||||
container.style.maxHeight = container.scrollHeight + "px";
|
||||
document.querySelectorAll('.dropdown-item').forEach((link) => {
|
||||
if (favoritesMode) {
|
||||
link.dataset.originalHref = link.getAttribute('href');
|
||||
link.setAttribute('href', '#');
|
||||
link.classList.add('no-hover');
|
||||
} else {
|
||||
link.setAttribute('href', link.dataset.originalHref || '#');
|
||||
link.classList.remove('no-hover');
|
||||
}
|
||||
});
|
||||
|
||||
const isFavoritesView = JSON.parse(localStorage.getItem('favoritesView') || 'false');
|
||||
if (favoritesMode && !isFavoritesView) {
|
||||
toggleFavoritesView();
|
||||
}
|
||||
}
|
||||
|
||||
function toggleFavoritesView() {
|
||||
const isFavoritesView = JSON.parse(localStorage.getItem('favoritesView') || 'false');
|
||||
localStorage.setItem('favoritesView', !isFavoritesView);
|
||||
updateFavoritesView();
|
||||
}
|
||||
window.onload = function () {
|
||||
initializeCards();
|
||||
};
|
||||
|
||||
function sortNavElements(criteria) {
|
||||
document.querySelectorAll('.nav-group-container').forEach((container) => {
|
||||
const items = Array.from(container.children);
|
||||
|
||||
items.sort((a, b) => {
|
||||
if (criteria === 'alphabetical') {
|
||||
const titleA = a.querySelector('.icon-text')?.textContent.trim().toLowerCase() || '';
|
||||
const titleB = b.querySelector('.icon-text')?.textContent.trim().toLowerCase() || '';
|
||||
return titleA.localeCompare(titleB);
|
||||
} else if (criteria === 'global') {
|
||||
const popularityA = parseInt(a.dataset.popularity, 10) || 1000;
|
||||
const popularityB = parseInt(b.dataset.popularity, 10) || 1000;
|
||||
return popularityA - popularityB;
|
||||
}
|
||||
return 0;
|
||||
});
|
||||
container.innerHTML = '';
|
||||
items.forEach((item) => container.appendChild(item));
|
||||
});
|
||||
}
|
||||
|
||||
async function fetchPopularityData(url) {
|
||||
const response = await fetch(url);
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP error! status: ${response.status}`);
|
||||
}
|
||||
return await response.text();
|
||||
}
|
||||
|
||||
function applyPopularityData(popularityData) {
|
||||
document.querySelectorAll('.dropdown-item').forEach((item) => {
|
||||
const endpoint = item.getAttribute('data-bs-link');
|
||||
const popularity = popularityData['/' + endpoint];
|
||||
if (endpoint && popularity !== undefined) {
|
||||
item.setAttribute('data-popularity', popularity);
|
||||
}
|
||||
});
|
||||
const currentSort = localStorage.getItem('homepageSort') || 'alphabetical';
|
||||
const sortDropdown = document.getElementById('sort-options');
|
||||
if (sortDropdown) {
|
||||
sortDropdown.value = currentSort;
|
||||
``;
|
||||
}
|
||||
sortNavElements(currentSort);
|
||||
}
|
||||
document.addEventListener('DOMContentLoaded', async function () {
|
||||
const sortDropdown = document.getElementById('sort-options');
|
||||
if (sortDropdown) {
|
||||
sortDropdown.addEventListener('change', (event) => {
|
||||
const selectedOption = event.target.value;
|
||||
localStorage.setItem('homepageSort', selectedOption);
|
||||
|
||||
sortNavElements(selectedOption);
|
||||
});
|
||||
}
|
||||
try {
|
||||
const response = await fetch('files/popularity.txt');
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP error! status: ${response.status}`);
|
||||
}
|
||||
const popularityData = await response.json();
|
||||
applyPopularityData(popularityData);
|
||||
} catch (error) {
|
||||
console.error('Error loading popularity data:', error);
|
||||
}
|
||||
|
||||
const materialIcons = new FontFaceObserver('Material Symbols Rounded');
|
||||
|
||||
materialIcons
|
||||
.load()
|
||||
.then(() => {
|
||||
document.querySelectorAll('.dropdown-item.hidden').forEach((el) => {
|
||||
el.classList.remove('hidden');
|
||||
});
|
||||
})
|
||||
.catch(() => {
|
||||
console.error('Material Symbols Rounded font failed to load.');
|
||||
});
|
||||
|
||||
Array.from(document.querySelectorAll('.feature-group-header')).forEach((header) => {
|
||||
const parent = header.parentNode;
|
||||
header.onclick = () => {
|
||||
expandCollapseToggle(parent);
|
||||
};
|
||||
})
|
||||
|
||||
const collapsed = localStorage.getItem("collapsedGroups") ? JSON.parse(localStorage.getItem("collapsedGroups")) : [];
|
||||
const groupsArray = Array.from(document.querySelectorAll(".feature-group"));
|
||||
|
||||
groupsArray.forEach(group => {
|
||||
if (collapsed.indexOf(group.id) !== -1) {
|
||||
expandCollapseToggle(group, false);
|
||||
}
|
||||
})
|
||||
|
||||
// Necessary in order to not fire the transition animation on page load, which looks wrong.
|
||||
// The timeout isn't doing anything visible to the user, so it's not making the page load look slower.
|
||||
setTimeout(() => {
|
||||
groupsArray.forEach(group => {
|
||||
const container = group.querySelector(".feature-group-container");
|
||||
container.classList.add("animated-group");
|
||||
})
|
||||
}, 500);
|
||||
|
||||
showFavoritesOnly();
|
||||
});
|
||||
});
|
||||
|
@ -81,7 +81,7 @@ class DragDropManager {
|
||||
}
|
||||
|
||||
onDragEl(mouseEvent) {
|
||||
const {clientX, clientY} = mouseEvent;
|
||||
const { clientX, clientY } = mouseEvent;
|
||||
if (this.draggedImageEl) {
|
||||
this.draggedImageEl.style.visibility = 'visible';
|
||||
this.draggedImageEl.style.left = `${clientX}px`;
|
||||
@ -174,7 +174,7 @@ class DragDropManager {
|
||||
this.elementTimeouts.set(element, timeoutId);
|
||||
}
|
||||
|
||||
setActions({movePageTo}) {
|
||||
setActions({ movePageTo }) {
|
||||
this.movePageTo = movePageTo;
|
||||
}
|
||||
|
||||
|
@ -129,32 +129,37 @@ class PdfActionsManager {
|
||||
|
||||
const moveUp = document.createElement("button");
|
||||
moveUp.classList.add("pdf-actions_move-left-button", "btn", "btn-secondary");
|
||||
moveUp.innerHTML = `<span class="material-symbols-rounded">arrow_${leftDirection}_alt</span><span class="btn-tooltip">${window.translations.moveLeft}</span>`;
|
||||
moveUp.setAttribute('title', window.translations.moveLeft);
|
||||
moveUp.innerHTML = `<span class="material-symbols-rounded">arrow_${leftDirection}_alt</span>`;
|
||||
moveUp.onclick = this.moveUpButtonCallback;
|
||||
buttonContainer.appendChild(moveUp);
|
||||
|
||||
const moveDown = document.createElement("button");
|
||||
moveDown.classList.add("pdf-actions_move-right-button", "btn", "btn-secondary");
|
||||
moveDown.innerHTML = `<span class="material-symbols-rounded">arrow_${rightDirection}_alt</span><span class="btn-tooltip">${window.translations.moveRight}</span>`;
|
||||
moveDown.setAttribute('title', window.translations.moveRight);
|
||||
moveDown.innerHTML = `<span class="material-symbols-rounded">arrow_${rightDirection}_alt</span>`;
|
||||
moveDown.onclick = this.moveDownButtonCallback;
|
||||
buttonContainer.appendChild(moveDown);
|
||||
|
||||
|
||||
const rotateCCW = document.createElement("button");
|
||||
rotateCCW.classList.add("btn", "btn-secondary");
|
||||
rotateCCW.innerHTML = `<span class="material-symbols-rounded">rotate_left</span><span class="btn-tooltip">${window.translations.rotateLeft}</span>`;
|
||||
rotateCCW.setAttribute('title', window.translations.rotateLeft);
|
||||
rotateCCW.innerHTML = `<span class="material-symbols-rounded">rotate_left</span>`;
|
||||
rotateCCW.onclick = this.rotateCCWButtonCallback;
|
||||
buttonContainer.appendChild(rotateCCW);
|
||||
|
||||
const rotateCW = document.createElement("button");
|
||||
rotateCW.classList.add("btn", "btn-secondary");
|
||||
rotateCW.innerHTML = `<span class="material-symbols-rounded">rotate_right</span><span class="btn-tooltip">${window.translations.rotateRight}</span>`;
|
||||
rotateCW.setAttribute('title', window.translations.rotateRight);
|
||||
rotateCW.innerHTML = `<span class="material-symbols-rounded">rotate_right</span>`;
|
||||
rotateCW.onclick = this.rotateCWButtonCallback;
|
||||
buttonContainer.appendChild(rotateCW);
|
||||
|
||||
const deletePage = document.createElement("button");
|
||||
deletePage.classList.add("btn", "btn-danger");
|
||||
deletePage.innerHTML = `<span class="material-symbols-rounded">delete</span><span class="btn-tooltip"></span><span class="btn-tooltip">${window.translations.delete}</span>`;
|
||||
deletePage.setAttribute('title', window.translations.delete);
|
||||
deletePage.innerHTML = `<span class="material-symbols-rounded">delete</span>`;
|
||||
deletePage.onclick = this.deletePageButtonCallback;
|
||||
buttonContainer.appendChild(deletePage);
|
||||
|
||||
@ -194,19 +199,22 @@ class PdfActionsManager {
|
||||
|
||||
const insertFileButton = document.createElement("button");
|
||||
insertFileButton.classList.add("btn", "btn-primary", "pdf-actions_insert-file-button");
|
||||
insertFileButton.innerHTML = `<span class="material-symbols-rounded">add</span></span><span class="btn-tooltip">${window.translations.addFile}</span>`;
|
||||
moveUp.setAttribute('title', window.translations.addFile);
|
||||
insertFileButton.innerHTML = `<span class="material-symbols-rounded">add</span>`;
|
||||
insertFileButton.onclick = this.insertFileButtonCallback;
|
||||
insertFileButtonContainer.appendChild(insertFileButton);
|
||||
|
||||
const splitFileButton = document.createElement("button");
|
||||
splitFileButton.classList.add("btn", "btn-primary", "pdf-actions_split-file-button");
|
||||
splitFileButton.innerHTML = `<span class="material-symbols-rounded">cut</span></span><span class="btn-tooltip">${window.translations.split}</span>`;
|
||||
splitFileButton.setAttribute('title', window.translations.split);
|
||||
splitFileButton.innerHTML = `<span class="material-symbols-rounded">cut</span>`;
|
||||
splitFileButton.onclick = this.splitFileButtonCallback;
|
||||
insertFileButtonContainer.appendChild(splitFileButton);
|
||||
|
||||
const insertFileBlankButton = document.createElement("button");
|
||||
insertFileBlankButton.classList.add("btn", "btn-primary", "pdf-actions_insert-file-blank-button");
|
||||
insertFileBlankButton.innerHTML = `<span class="material-symbols-rounded">insert_page_break</span></span><span class="btn-tooltip">${window.translations.insertPageBreak}</span>`;
|
||||
insertFileBlankButton.setAttribute('title', window.translations.insertPageBreak);
|
||||
insertFileBlankButton.innerHTML = `<span class="material-symbols-rounded">insert_page_break</span>`;
|
||||
insertFileBlankButton.onclick = this.insertFileBlankButtonCallback;
|
||||
insertFileButtonContainer.appendChild(insertFileBlankButton);
|
||||
|
||||
@ -261,10 +269,8 @@ class PdfActionsManager {
|
||||
document.addEventListener("selectedPagesUpdated", () => {
|
||||
window.updateSelectedPagesDisplay();
|
||||
});
|
||||
|
||||
return div;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default PdfActionsManager;
|
||||
|
@ -1,11 +1,11 @@
|
||||
import {MovePageUpCommand, MovePageDownCommand} from './commands/move-page.js';
|
||||
import {RemoveSelectedCommand} from './commands/remove.js';
|
||||
import {RotateAllCommand, RotateElementCommand} from './commands/rotate.js';
|
||||
import {SplitAllCommand} from './commands/split.js';
|
||||
import {UndoManager} from './UndoManager.js';
|
||||
import {PageBreakCommand} from './commands/page-break.js';
|
||||
import {AddFilesCommand} from './commands/add-page.js';
|
||||
import {DecryptFile} from '../DecryptFiles.js';
|
||||
import { MovePageUpCommand, MovePageDownCommand } from './commands/move-page.js';
|
||||
import { RemoveSelectedCommand } from './commands/remove.js';
|
||||
import { RotateAllCommand, RotateElementCommand } from './commands/rotate.js';
|
||||
import { SplitAllCommand } from './commands/split.js';
|
||||
import { UndoManager } from './UndoManager.js';
|
||||
import { PageBreakCommand } from './commands/page-break.js';
|
||||
import { AddFilesCommand } from './commands/add-page.js';
|
||||
import { DecryptFile } from '../DecryptFiles.js';
|
||||
|
||||
class PdfContainer {
|
||||
fileName;
|
||||
@ -144,6 +144,8 @@ class PdfContainer {
|
||||
await addFilesCommand.execute();
|
||||
|
||||
this.undoManager.pushUndoClearRedo(addFilesCommand);
|
||||
window.tooltipSetup();
|
||||
|
||||
}
|
||||
|
||||
async addFilesAction(nextSiblingElement) {
|
||||
@ -212,7 +214,7 @@ class PdfContainer {
|
||||
}
|
||||
|
||||
if (decryptedFile.type === 'application/pdf') {
|
||||
const {renderer, pdfDocument} = await this.loadFile(decryptedFile);
|
||||
const { renderer, pdfDocument } = await this.loadFile(decryptedFile);
|
||||
pageCount = renderer.pageCount || 0;
|
||||
pages = await this.addPdfFile(renderer, pdfDocument, nextSiblingElement, pages);
|
||||
} else if (decryptedFile.type.startsWith('image/')) {
|
||||
@ -247,14 +249,14 @@ class PdfContainer {
|
||||
pdf_pages: pageCount,
|
||||
});
|
||||
}
|
||||
} catch {}
|
||||
} catch { }
|
||||
}
|
||||
|
||||
async addFilesBlank(nextSiblingElement, pages) {
|
||||
let doc = await PDFLib.PDFDocument.create();
|
||||
let docBytes = await doc.save();
|
||||
|
||||
const url = URL.createObjectURL(new Blob([docBytes], {type: 'application/pdf'}));
|
||||
const url = URL.createObjectURL(new Blob([docBytes], { type: 'application/pdf' }));
|
||||
|
||||
const renderer = await this.toRenderer(url);
|
||||
pages = await this.addPdfFile(renderer, doc, nextSiblingElement, pages);
|
||||
@ -324,7 +326,7 @@ class PdfContainer {
|
||||
var objectUrl = URL.createObjectURL(file);
|
||||
var pdfDocument = await this.toPdfLib(objectUrl);
|
||||
var renderer = await this.toRenderer(objectUrl);
|
||||
return {renderer, pdfDocument};
|
||||
return { renderer, pdfDocument };
|
||||
}
|
||||
|
||||
async toRenderer(objectUrl) {
|
||||
@ -350,7 +352,7 @@ class PdfContainer {
|
||||
// render the page onto the canvas
|
||||
var renderContext = {
|
||||
canvasContext: canvas.getContext('2d'),
|
||||
viewport: page.getViewport({scale: 1}),
|
||||
viewport: page.getViewport({ scale: 1 }),
|
||||
};
|
||||
|
||||
await page.render(renderContext).promise;
|
||||
@ -604,7 +606,7 @@ class PdfContainer {
|
||||
|
||||
let firstPage = splitterIndex === 0 ? 0 : splitters[splitterIndex - 1];
|
||||
|
||||
const pageIndices = Array.from({length: splitterPosition - firstPage}, (value, key) => firstPage + key);
|
||||
const pageIndices = Array.from({ length: splitterPosition - firstPage }, (value, key) => firstPage + key);
|
||||
|
||||
const copiedPages = await subDocument.copyPages(baseDocument, pageIndices);
|
||||
|
||||
@ -687,7 +689,7 @@ class PdfContainer {
|
||||
pdfDoc.setProducer(stirlingPDFLabel);
|
||||
|
||||
const pdfBytes = await pdfDoc.save();
|
||||
const pdfBlob = new Blob([pdfBytes], {type: 'application/pdf'});
|
||||
const pdfBlob = new Blob([pdfBytes], { type: 'application/pdf' });
|
||||
|
||||
const filenameInput = document.getElementById('filename-input');
|
||||
|
||||
@ -722,7 +724,7 @@ class PdfContainer {
|
||||
const archivedDocuments = await this.nameAndArchiveFiles(splitDocuments, baseName);
|
||||
|
||||
const self = this;
|
||||
archivedDocuments.generateAsync({type: 'base64'}).then(function (base64) {
|
||||
archivedDocuments.generateAsync({ type: 'base64' }).then(function (base64) {
|
||||
const url = 'data:application/zip;base64,' + base64;
|
||||
self.downloadLink = document.createElement('a');
|
||||
self.downloadLink.href = url;
|
||||
|
@ -1,46 +1,79 @@
|
||||
function toolsManager() {
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
const stackedContainer = document.getElementById('stacked');
|
||||
const convertToPDF = document.querySelector('#groupConvertTo');
|
||||
const convertFromPDF = document.querySelector('#groupConvertFrom');
|
||||
|
||||
if (stackedContainer) {
|
||||
const convertToPDF = stackedContainer.querySelector('.navbar-item:first-child');
|
||||
const convertFromPDF = stackedContainer.querySelector('.navbar-item:nth-child(2)');
|
||||
if (convertToPDF && convertFromPDF) {
|
||||
const itemsTo = Array.from(convertToPDF.querySelectorAll('.dropdown-item')).filter(
|
||||
(item) => !item.querySelector('hr.dropdown-divider')
|
||||
);
|
||||
const itemsFrom = Array.from(convertFromPDF.querySelectorAll('.dropdown-item')).filter(
|
||||
(item) => !item.querySelector('hr.dropdown-divider')
|
||||
);
|
||||
|
||||
if (convertToPDF && convertFromPDF) {
|
||||
const dropdownItemsTo = convertToPDF.querySelectorAll('.dropdown-item');
|
||||
const dropdownItemsFrom = convertFromPDF.querySelectorAll('.dropdown-item');
|
||||
const totalItems = itemsTo.length + itemsFrom.length;
|
||||
|
||||
const itemsTo = Array.from(dropdownItemsTo).filter((item) => !item.querySelector('hr.dropdown-divider'));
|
||||
const itemsFrom = Array.from(dropdownItemsFrom).filter((item) => !item.querySelector('hr.dropdown-divider'));
|
||||
if (totalItems > 12) {
|
||||
document.querySelectorAll('#convertGroup').forEach((element) => (element.style.display = 'none'));
|
||||
document.querySelectorAll('#groupConvertTo').forEach((element) => (element.style.display = 'flex'));
|
||||
document.querySelectorAll('#groupConvertFrom').forEach((element) => (element.style.display = 'flex'));
|
||||
} else {
|
||||
document.querySelectorAll('#convertGroup').forEach((element) => (element.style.display = 'flex'));
|
||||
document.querySelectorAll('#groupConvertTo').forEach((element) => (element.style.display = 'none'));
|
||||
document.querySelectorAll('#groupConvertFrom').forEach((element) => (element.style.display = 'none'));
|
||||
}
|
||||
}
|
||||
|
||||
const totalItems = itemsTo.length + itemsFrom.length;
|
||||
document.querySelectorAll('.navbar-item').forEach((element) => {
|
||||
if (!element.closest('#stacked')) {
|
||||
const dropdownItems = element.querySelectorAll('.dropdown-item');
|
||||
const items = Array.from(dropdownItems).filter((item) => !item.querySelector('hr.dropdown-divider'));
|
||||
|
||||
if (totalItems > 12) {
|
||||
stackedContainer.style.flexDirection = 'row';
|
||||
stackedContainer.classList.remove('col-lg-2');
|
||||
stackedContainer.classList.add('col-lg-4');
|
||||
convertToPDF.style.flex = '1 1 50%';
|
||||
convertFromPDF.style.flex = '1 1 50%';
|
||||
if (items.length === 0) {
|
||||
if (
|
||||
element.previousElementSibling &&
|
||||
element.previousElementSibling.classList.contains('navbar-item') &&
|
||||
element.previousElementSibling.classList.contains('nav-item-separator')
|
||||
) {
|
||||
element.previousElementSibling.remove();
|
||||
}
|
||||
element.remove();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
document.querySelectorAll('.navbar-item').forEach((element) => {
|
||||
if (!element.closest('#stacked')) {
|
||||
const dropdownItems = element.querySelectorAll('.dropdown-item');
|
||||
const items = Array.from(dropdownItems).filter((item) => !item.querySelector('hr.dropdown-divider'));
|
||||
window.tooltipSetup = () => {
|
||||
const tooltipElements = document.querySelectorAll("[title]");
|
||||
|
||||
if (items.length === 0) {
|
||||
if (
|
||||
element.previousElementSibling &&
|
||||
element.previousElementSibling.classList.contains('navbar-item') &&
|
||||
element.previousElementSibling.classList.contains('nav-item-separator')
|
||||
) {
|
||||
element.previousElementSibling.remove();
|
||||
}
|
||||
element.remove();
|
||||
}
|
||||
}
|
||||
tooltipElements.forEach((element) => {
|
||||
const tooltipText = element.getAttribute("title");
|
||||
element.removeAttribute("title");
|
||||
|
||||
const customTooltip = document.createElement("div");
|
||||
customTooltip.className = "btn-tooltip";
|
||||
customTooltip.textContent = tooltipText;
|
||||
|
||||
document.body.appendChild(customTooltip);
|
||||
|
||||
element.addEventListener("mouseenter", (event) => {
|
||||
customTooltip.style.display = "block";
|
||||
customTooltip.style.left = `${event.pageX + 10}px`; // Position tooltip slightly away from the cursor
|
||||
customTooltip.style.top = `${event.pageY + 10}px`;
|
||||
});
|
||||
|
||||
// Update the position of the tooltip as the user moves the mouse
|
||||
element.addEventListener("mousemove", (event) => {
|
||||
customTooltip.style.left = `${event.pageX + 10}px`;
|
||||
customTooltip.style.top = `${event.pageY + 10}px`;
|
||||
});
|
||||
|
||||
|
||||
// Hide the tooltip when the mouse leaves
|
||||
element.addEventListener("mouseleave", () => {
|
||||
customTooltip.style.display = "none";
|
||||
});
|
||||
});
|
||||
}
|
||||
document.addEventListener("DOMContentLoaded", () => {
|
||||
tooltipSetup();
|
||||
});
|
||||
|
182
src/main/resources/static/js/pages/home.js
Normal file
182
src/main/resources/static/js/pages/home.js
Normal file
@ -0,0 +1,182 @@
|
||||
/*<![CDATA[*/
|
||||
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
if (window.analyticsPromptBoolean) {
|
||||
const analyticsModal = new bootstrap.Modal(document.getElementById('analyticsModal'));
|
||||
analyticsModal.show();
|
||||
}
|
||||
});
|
||||
/*]]>*/
|
||||
function setAnalytics(enabled) {
|
||||
fetchWithCsrf('api/v1/settings/update-enable-analytics', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify(enabled),
|
||||
})
|
||||
.then((response) => {
|
||||
if (response.status === 200) {
|
||||
console.log('Analytics setting updated successfully');
|
||||
bootstrap.Modal.getInstance(document.getElementById('analyticsModal')).hide();
|
||||
} else if (response.status === 208) {
|
||||
console.log('Analytics setting has already been set. Please edit /config/settings.yml to change it.', response);
|
||||
alert('Analytics setting has already been set. Please edit /config/settings.yml to change it.');
|
||||
} else {
|
||||
throw new Error('Unexpected response status: ' + response.status);
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error('Error updating analytics setting:', error);
|
||||
alert('An error occurred while updating the analytics setting. Please try again.');
|
||||
});
|
||||
}
|
||||
|
||||
updateFavoriteIcons();
|
||||
|
||||
const defaultView = localStorage.getItem('defaultView') || 'home'; // Default to "home"
|
||||
if (defaultView === 'home-legacy') {
|
||||
window.location.href = '/home-legacy'; // Redirect to legacy view
|
||||
}
|
||||
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
const surveyVersion = '2.0';
|
||||
const modal = new bootstrap.Modal(document.getElementById('surveyModal'));
|
||||
const dontShowAgain = document.getElementById('dontShowAgain');
|
||||
const takeSurveyButton = document.getElementById('takeSurvey');
|
||||
|
||||
const viewThresholds = [5, 10, 15, 22, 30, 50, 75, 100, 150, 200];
|
||||
|
||||
// Check if survey version changed and reset page views if it did
|
||||
const storedVersion = localStorage.getItem('surveyVersion');
|
||||
if (storedVersion && storedVersion !== surveyVersion) {
|
||||
localStorage.setItem('pageViews', '0');
|
||||
}
|
||||
|
||||
let pageViews = parseInt(localStorage.getItem('pageViews') || '0');
|
||||
|
||||
pageViews++;
|
||||
localStorage.setItem('pageViews', pageViews.toString());
|
||||
|
||||
function shouldShowSurvey() {
|
||||
if (localStorage.getItem('dontShowSurvey') === 'true' || localStorage.getItem('surveyTaken') === 'true') {
|
||||
return false;
|
||||
}
|
||||
|
||||
// If survey version changed and we hit a threshold, show the survey
|
||||
if (localStorage.getItem('surveyVersion') !== surveyVersion && viewThresholds.includes(pageViews)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return viewThresholds.includes(pageViews);
|
||||
}
|
||||
|
||||
if (shouldShowSurvey()) {
|
||||
modal.show();
|
||||
}
|
||||
|
||||
dontShowAgain.addEventListener('change', function () {
|
||||
if (this.checked) {
|
||||
localStorage.setItem('dontShowSurvey', 'true');
|
||||
localStorage.setItem('surveyVersion', surveyVersion);
|
||||
} else {
|
||||
localStorage.removeItem('dontShowSurvey');
|
||||
localStorage.removeItem('surveyVersion');
|
||||
}
|
||||
});
|
||||
|
||||
takeSurveyButton.addEventListener('click', function () {
|
||||
localStorage.setItem('surveyTaken', 'true');
|
||||
localStorage.setItem('surveyVersion', surveyVersion);
|
||||
modal.hide();
|
||||
});
|
||||
|
||||
if (localStorage.getItem('dontShowSurvey')) {
|
||||
modal.hide();
|
||||
}
|
||||
|
||||
if (window.location.pathname === '/') {
|
||||
const navItem = document.getElementById('navItemToHide');
|
||||
if (navItem) {
|
||||
navItem.style.display = 'none';
|
||||
}
|
||||
}
|
||||
updateFavoritesDropdown();
|
||||
});
|
||||
function setAsDefault(value) {
|
||||
localStorage.setItem('defaultView', value);
|
||||
console.log(`Default view set to: ${value}`);
|
||||
}
|
||||
|
||||
function adjustVisibleElements() {
|
||||
const container = document.querySelector('.recent-features');
|
||||
const subElements = Array.from(container.children);
|
||||
|
||||
let totalWidth = 0;
|
||||
const containerWidth = container.offsetWidth;
|
||||
|
||||
subElements.forEach((element) => {
|
||||
totalWidth += 12 * parseFloat(getComputedStyle(document.documentElement).fontSize);
|
||||
|
||||
if (totalWidth > window.innerWidth) {
|
||||
element.style.display = 'none';
|
||||
} else {
|
||||
element.style.display = 'block';
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function adjustContainerAlignment() {
|
||||
console.log('Adjusting container alignment');
|
||||
|
||||
document.querySelectorAll('.features-container').forEach((parent) => {
|
||||
parent.querySelectorAll('.feature-rows').forEach((container) => {
|
||||
const childElements = Array.from(container.children);
|
||||
|
||||
const containerWidth = parent.offsetWidth;
|
||||
console.log(containerWidth < 32 * parseFloat(getComputedStyle(document.documentElement).fontSize));
|
||||
if (containerWidth < 32 * parseFloat(getComputedStyle(document.documentElement).fontSize)) {
|
||||
container.classList.add('single-column');
|
||||
} else {
|
||||
container.classList.remove('single-column');
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
function toolsManager() {
|
||||
const convertToPDF = document.querySelector('#groupConvertTo');
|
||||
const convertFromPDF = document.querySelector('#groupConvertFrom');
|
||||
|
||||
if (convertToPDF && convertFromPDF) {
|
||||
const itemsTo = Array.from(convertToPDF.querySelectorAll('.dropdown-item')).filter(
|
||||
(item) => !item.querySelector('hr.dropdown-divider')
|
||||
);
|
||||
const itemsFrom = Array.from(convertFromPDF.querySelectorAll('.dropdown-item')).filter(
|
||||
(item) => !item.querySelector('hr.dropdown-divider')
|
||||
);
|
||||
|
||||
const totalItems = itemsTo.length + itemsFrom.length;
|
||||
|
||||
if (totalItems > 12) {
|
||||
document.querySelectorAll('#convertGroup').forEach((element) => element.remove());
|
||||
document.querySelectorAll('#groupConvertTo').forEach((element) => (element.style.display = 'flex'));
|
||||
document.querySelectorAll('#groupConvertFrom').forEach((element) => (element.style.display = 'flex'));
|
||||
} else {
|
||||
document.querySelectorAll('#convertGroup').forEach((element) => (element.style.display = 'flex'));
|
||||
document.querySelectorAll('#groupConvertTo').forEach((element) => element.remove());
|
||||
document.querySelectorAll('#groupConvertFrom').forEach((element) => element.remove());
|
||||
}
|
||||
}
|
||||
}
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
toolsManager();
|
||||
});
|
||||
|
||||
window.addEventListener('load', () => {
|
||||
adjustContainerAlignment();
|
||||
adjustVisibleElements();
|
||||
});
|
||||
window.addEventListener('resize', () => {
|
||||
adjustContainerAlignment();
|
||||
adjustVisibleElements();
|
||||
});
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -732,6 +732,7 @@
|
||||
}
|
||||
|
||||
:root{
|
||||
--navbar-height: 64px;
|
||||
--xfa-unfocused-field-background:url("data:image/svg+xml;charset=UTF-8,<svg width='1px' height='1px' xmlns='http://www.w3.org/2000/svg'><rect width='100%' height='100%' style='fill:rgba(0, 54, 255, 0.13);'/></svg>");
|
||||
--xfa-focus-outline:auto;
|
||||
}
|
||||
@ -3043,8 +3044,9 @@ body{
|
||||
|
||||
#outerContainer{
|
||||
width:100%;
|
||||
height:100%;
|
||||
height: calc(100% - var(--navbar-height));
|
||||
position:relative;
|
||||
|
||||
}
|
||||
|
||||
#sidebarContainer{
|
||||
|
7131
src/main/resources/static/pdfjs/css/viewer.css
vendored
7131
src/main/resources/static/pdfjs/css/viewer.css
vendored
File diff suppressed because it is too large
Load Diff
@ -16,12 +16,14 @@
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-md-6 bg-card">
|
||||
<div class="tool-header">
|
||||
<span class="material-symbols-rounded tool-header-icon convert">draft</span>
|
||||
<span class="material-symbols-rounded tool-header-icon convertto">draft</span>
|
||||
<span class="tool-header-text" th:text="#{fileToPDF.header}"></span>
|
||||
</div>
|
||||
<p th:text="#{processTimeWarning}"></p>
|
||||
<form method="post" enctype="multipart/form-data" th:action="@{'/api/v1/convert/file/pdf'}">
|
||||
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multipleInputsForSingleRequest=false)}"></div>
|
||||
<div
|
||||
th:replace="~{fragments/common :: fileSelector(name='fileInput', multipleInputsForSingleRequest=false)}">
|
||||
</div>
|
||||
<a class="btn btn-outline-primary" data-bs-toggle="collapse" href="#info" role="button"
|
||||
aria-expanded="false" aria-controls="info" th:text="#{fileToPDF.supportedFileTypesInfo}"></a>
|
||||
<div class="collapse" id="info">
|
||||
@ -42,7 +44,7 @@
|
||||
href="https://help.libreoffice.org/latest/en-US/text/shared/guide/supported_formats.html">https://help.libreoffice.org/latest/en-US/text/shared/guide/supported_formats.html</a>
|
||||
</div>
|
||||
<div>
|
||||
<br/>
|
||||
<br />
|
||||
<button type="submit" id="submitBtn" class="btn btn-primary" th:text="#{fileToPDF.submit}"></button>
|
||||
</div>
|
||||
</form>
|
||||
|
@ -1,38 +1,43 @@
|
||||
<!DOCTYPE html>
|
||||
<html th:lang="${#locale.language}" th:dir="#{language.direction}" th:data-language="${#locale.toString()}" xmlns:th="https://www.thymeleaf.org">
|
||||
<head>
|
||||
<th:block th:insert="~{fragments/common :: head(title=#{HTMLToPDF.title}, header=#{HTMLToPDF.header})}"></th:block>
|
||||
</head>
|
||||
<html th:lang="${#locale.language}" th:dir="#{language.direction}" th:data-language="${#locale.toString()}"
|
||||
xmlns:th="https://www.thymeleaf.org">
|
||||
|
||||
<body>
|
||||
<th:block th:insert="~{fragments/common :: game}"></th:block>
|
||||
<div id="page-container">
|
||||
<div id="content-wrap">
|
||||
<th:block th:insert="~{fragments/navbar.html :: navbar}"></th:block>
|
||||
<br><br>
|
||||
<div class="container">
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-md-6 bg-card">
|
||||
<div class="tool-header">
|
||||
<span class="material-symbols-rounded tool-header-icon convert">html</span>
|
||||
<span class="tool-header-text" th:text="#{HTMLToPDF.header}"></span>
|
||||
</div>
|
||||
<form method="post" enctype="multipart/form-data" th:action="@{'/api/v1/convert/html/pdf'}">
|
||||
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multipleInputsForSingleRequest=false, accept='text/html,application/zip' )}"></div>
|
||||
<div class="mb-3">
|
||||
<label for="zoom" th:text="#{HTMLToPDF.zoom}" class="form-label"></label>
|
||||
<input type="number" step="0.1" class="form-control" id="zoom" name="zoom" value="1">
|
||||
</div>
|
||||
<br>
|
||||
<button type="submit" id="submitBtn" class="btn btn-primary" th:text="#{HTMLToPDF.submit}"></button>
|
||||
</form>
|
||||
<p class="mt-3" th:text="#{HTMLToPDF.help}"></p>
|
||||
<p class="mt-3" th:text="#{HTMLToPDF.credit}"></p>
|
||||
<head>
|
||||
<th:block th:insert="~{fragments/common :: head(title=#{HTMLToPDF.title}, header=#{HTMLToPDF.header})}"></th:block>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<th:block th:insert="~{fragments/common :: game}"></th:block>
|
||||
<div id="page-container">
|
||||
<div id="content-wrap">
|
||||
<th:block th:insert="~{fragments/navbar.html :: navbar}"></th:block>
|
||||
<br><br>
|
||||
<div class="container">
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-md-6 bg-card">
|
||||
<div class="tool-header">
|
||||
<span class="material-symbols-rounded tool-header-icon convertto">html</span>
|
||||
<span class="tool-header-text" th:text="#{HTMLToPDF.header}"></span>
|
||||
</div>
|
||||
<form method="post" enctype="multipart/form-data" th:action="@{'/api/v1/convert/html/pdf'}">
|
||||
<div
|
||||
th:replace="~{fragments/common :: fileSelector(name='fileInput', multipleInputsForSingleRequest=false, accept='text/html,application/zip' )}">
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="zoom" th:text="#{HTMLToPDF.zoom}" class="form-label"></label>
|
||||
<input type="number" step="0.1" class="form-control" id="zoom" name="zoom" value="1">
|
||||
</div>
|
||||
<br>
|
||||
<button type="submit" id="submitBtn" class="btn btn-primary" th:text="#{HTMLToPDF.submit}"></button>
|
||||
</form>
|
||||
<p class="mt-3" th:text="#{HTMLToPDF.help}"></p>
|
||||
<p class="mt-3" th:text="#{HTMLToPDF.credit}"></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<th:block th:insert="~{fragments/footer.html :: footer}"></th:block>
|
||||
</div>
|
||||
</body>
|
||||
<th:block th:insert="~{fragments/footer.html :: footer}"></th:block>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
</html>
|
@ -1,60 +1,67 @@
|
||||
<!DOCTYPE html>
|
||||
<html th:lang="${#locale.language}" th:dir="#{language.direction}" th:data-language="${#locale.toString()}" xmlns:th="https://www.thymeleaf.org">
|
||||
<head>
|
||||
<html th:lang="${#locale.language}" th:dir="#{language.direction}" th:data-language="${#locale.toString()}"
|
||||
xmlns:th="https://www.thymeleaf.org">
|
||||
|
||||
<head>
|
||||
<th:block th:insert="~{fragments/common :: head(title=#{imageToPDF.title}, header=#{imageToPDF.header})}"></th:block>
|
||||
</head>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<th:block th:insert="~{fragments/common :: game}"></th:block>
|
||||
<div id="page-container">
|
||||
<div id="content-wrap">
|
||||
<th:block th:insert="~{fragments/navbar.html :: navbar}"></th:block>
|
||||
<br><br>
|
||||
<div class="container">
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-md-6 bg-card">
|
||||
<div class="tool-header">
|
||||
<span class="material-symbols-rounded tool-header-icon image">image</span>
|
||||
<span class="tool-header-text" th:text="#{imageToPDF.header}"></span>
|
||||
<body>
|
||||
<th:block th:insert="~{fragments/common :: game}"></th:block>
|
||||
<div id="page-container">
|
||||
<div id="content-wrap">
|
||||
<th:block th:insert="~{fragments/navbar.html :: navbar}"></th:block>
|
||||
<br><br>
|
||||
<div class="container">
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-md-6 bg-card">
|
||||
<div class="tool-header">
|
||||
<span class="material-symbols-rounded tool-header-icon convertto">picture_as_pdf</span>
|
||||
<span class="tool-header-text" th:text="#{imageToPDF.header}"></span>
|
||||
</div>
|
||||
<form id="imageToPDFForm" method="post" enctype="multipart/form-data"
|
||||
th:action="@{'/api/v1/convert/img/pdf'}">
|
||||
<div
|
||||
th:replace="~{fragments/common :: fileSelector(name='fileInput', multipleInputsForSingleRequest=false, accept='image/*', inputText=#{imgPrompt})}">
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="fitOption" th:text="#{imageToPDF.selectLabel}">Fit Options</label>
|
||||
<select class="form-control" id="fitOption" name="fitOption">
|
||||
<option value="fillPage" th:text="#{imageToPDF.fillPage}">Fill Page</option>
|
||||
<option value="fitDocumentToImage" th:text="#{imageToPDF.fitDocumentToImage}">Fit Document to Image
|
||||
</option>
|
||||
<option value="maintainAspectRatio" th:text="#{imageToPDF.maintainAspectRatio}">Maintain Aspect Ratio
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
<form id="imageToPDFForm" method="post" enctype="multipart/form-data" th:action="@{'/api/v1/convert/img/pdf'}">
|
||||
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multipleInputsForSingleRequest=false, accept='image/*', inputText=#{imgPrompt})}"></div>
|
||||
<div class="mb-3">
|
||||
<label for="fitOption" th:text="#{imageToPDF.selectLabel}">Fit Options</label>
|
||||
<select class="form-control" id="fitOption" name="fitOption">
|
||||
<option value="fillPage" th:text="#{imageToPDF.fillPage}">Fill Page</option>
|
||||
<option value="fitDocumentToImage" th:text="#{imageToPDF.fitDocumentToImage}">Fit Document to Image</option>
|
||||
<option value="maintainAspectRatio" th:text="#{imageToPDF.maintainAspectRatio}">Maintain Aspect Ratio</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="form-check ms-3">
|
||||
<input type="checkbox" name="autoRotate" id="autoRotate">
|
||||
<label for="autoRotate" th:text=#{imageToPDF.selectText.2}></label>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label th:text="#{pdfToImage.colorType}"></label>
|
||||
<select class="form-control" id="colorType" name="colorType">
|
||||
<option value="color" th:text="#{pdfToImage.color}"></option>
|
||||
<option value="greyscale" th:text="#{pdfToImage.grey}"></option>
|
||||
<option value="blackwhite" th:text="#{pdfToImage.blackwhite}"></option>
|
||||
</select>
|
||||
</div>
|
||||
<input type="hidden" id="override" name="override" value="multi">
|
||||
<div class="mb-3">
|
||||
<label th:text=#{imageToPDF.selectText.3}></label>
|
||||
<select class="form-control" id="conversionType" name="conversionType" disabled>
|
||||
<option value="merge" th:text=#{imageToPDF.selectText.4}></option>
|
||||
<option value="convert" th:text=#{imageToPDF.selectText.5} selected></option>
|
||||
</select>
|
||||
</div>
|
||||
<br>
|
||||
<button type="submit" id="submitBtn" class="btn btn-primary" th:text="#{imageToPDF.submit}"></button>
|
||||
<script>
|
||||
$('#fileInput-input').on('change', function(e) {
|
||||
const fileInput = e.target;
|
||||
fileInput.addEventListener('file-input-change', async (e) => {
|
||||
const {allFiles} = e.detail;
|
||||
<div class="form-check ms-3">
|
||||
<input type="checkbox" name="autoRotate" id="autoRotate">
|
||||
<label for="autoRotate" th:text=#{imageToPDF.selectText.2}></label>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label th:text="#{pdfToImage.colorType}"></label>
|
||||
<select class="form-control" id="colorType" name="colorType">
|
||||
<option value="color" th:text="#{pdfToImage.color}"></option>
|
||||
<option value="greyscale" th:text="#{pdfToImage.grey}"></option>
|
||||
<option value="blackwhite" th:text="#{pdfToImage.blackwhite}"></option>
|
||||
</select>
|
||||
</div>
|
||||
<input type="hidden" id="override" name="override" value="multi">
|
||||
<div class="mb-3">
|
||||
<label th:text=#{imageToPDF.selectText.3}></label>
|
||||
<select class="form-control" id="conversionType" name="conversionType" disabled>
|
||||
<option value="merge" th:text=#{imageToPDF.selectText.4}></option>
|
||||
<option value="convert" th:text=#{imageToPDF.selectText.5} selected></option>
|
||||
</select>
|
||||
</div>
|
||||
<br>
|
||||
<button type="submit" id="submitBtn" class="btn btn-primary" th:text="#{imageToPDF.submit}"></button>
|
||||
<script>
|
||||
$('#fileInput-input').on('change', function (e) {
|
||||
const fileInput = e.target;
|
||||
fileInput.addEventListener('file-input-change', async (e) => {
|
||||
const { allFiles } = e.detail;
|
||||
var conversionType = document.getElementById("conversionType");
|
||||
console.log("files.length=" + allFiles.length)
|
||||
if (allFiles.length > 1) {
|
||||
@ -62,58 +69,59 @@
|
||||
} else {
|
||||
conversionType.disabled = true;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
$('#conversionType').change(function () {
|
||||
var selectedValue = $(this).val();
|
||||
var override = document.getElementById("override");
|
||||
console.log("selectedValue=" + selectedValue)
|
||||
if (selectedValue === 'merge') {
|
||||
override.value = "single";
|
||||
} else if (selectedValue === 'convert') {
|
||||
override.value = "multi";
|
||||
}
|
||||
});
|
||||
document.getElementById("imageToPDFForm").addEventListener("submit", async function (e) {
|
||||
e.preventDefault();
|
||||
|
||||
const form = e.target;
|
||||
const formData = new FormData(form);
|
||||
|
||||
const fitOptionSelect = document.getElementById("fitOption");
|
||||
const fitOptionValue = fitOptionSelect ? fitOptionSelect.value : "fit-to-page"; // Default value
|
||||
formData.append("fitOption", fitOptionValue);
|
||||
|
||||
const overrideInput = document.getElementById("override");
|
||||
console.log("Override value before submission:", overrideInput.value);
|
||||
|
||||
for (let [key, value] of formData.entries()) {
|
||||
console.log(`${key}:`, value);
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await fetch(form.action, {
|
||||
method: "POST",
|
||||
body: formData
|
||||
});
|
||||
});
|
||||
|
||||
$('#conversionType').change(function() {
|
||||
var selectedValue = $(this).val();
|
||||
var override = document.getElementById("override");
|
||||
console.log("selectedValue=" + selectedValue)
|
||||
if (selectedValue === 'merge') {
|
||||
override.value = "single";
|
||||
} else if (selectedValue === 'convert') {
|
||||
override.value = "multi";
|
||||
if (response.ok) {
|
||||
console.log("Form successfully submitted");
|
||||
} else {
|
||||
console.error("Failed to submit the form");
|
||||
}
|
||||
});
|
||||
document.getElementById("imageToPDFForm").addEventListener("submit", async function (e) {
|
||||
e.preventDefault();
|
||||
|
||||
const form = e.target;
|
||||
const formData = new FormData(form);
|
||||
|
||||
const fitOptionSelect = document.getElementById("fitOption");
|
||||
const fitOptionValue = fitOptionSelect ? fitOptionSelect.value : "fit-to-page"; // Default value
|
||||
formData.append("fitOption", fitOptionValue);
|
||||
|
||||
const overrideInput = document.getElementById("override");
|
||||
console.log("Override value before submission:", overrideInput.value);
|
||||
|
||||
for (let [key, value] of formData.entries()) {
|
||||
console.log(`${key}:`, value);
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await fetch(form.action, {
|
||||
method: "POST",
|
||||
body: formData
|
||||
});
|
||||
|
||||
if (response.ok) {
|
||||
console.log("Form successfully submitted");
|
||||
} else {
|
||||
console.error("Failed to submit the form");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error submitting the form:", error);
|
||||
}
|
||||
});
|
||||
</script>
|
||||
</form>
|
||||
</div>
|
||||
} catch (error) {
|
||||
console.error("Error submitting the form:", error);
|
||||
}
|
||||
});
|
||||
</script>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<th:block th:insert="~{fragments/footer.html :: footer}"></th:block>
|
||||
</div>
|
||||
</body>
|
||||
<th:block th:insert="~{fragments/footer.html :: footer}"></th:block>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
</html>
|
@ -1,33 +1,39 @@
|
||||
<!DOCTYPE html>
|
||||
<html th:lang="${#locale.language}" th:dir="#{language.direction}" th:data-language="${#locale.toString()}" xmlns:th="https://www.thymeleaf.org">
|
||||
<head>
|
||||
<th:block th:insert="~{fragments/common :: head(title=#{MarkdownToPDF.title}, header=#{MarkdownToPDF.header})}"></th:block>
|
||||
</head>
|
||||
<html th:lang="${#locale.language}" th:dir="#{language.direction}" th:data-language="${#locale.toString()}"
|
||||
xmlns:th="https://www.thymeleaf.org">
|
||||
|
||||
<body>
|
||||
<th:block th:insert="~{fragments/common :: game}"></th:block>
|
||||
<div id="page-container">
|
||||
<div id="content-wrap">
|
||||
<th:block th:insert="~{fragments/navbar.html :: navbar}"></th:block>
|
||||
<br><br>
|
||||
<div class="container">
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-md-6 bg-card">
|
||||
<div class="tool-header">
|
||||
<span class="material-symbols-rounded tool-header-icon convert">markdown</span>
|
||||
<span class="tool-header-text" th:text="#{MarkdownToPDF.header}"></span>
|
||||
</div>
|
||||
<form method="post" enctype="multipart/form-data" th:action="@{'/api/v1/convert/markdown/pdf'}">
|
||||
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multipleInputsForSingleRequest=false, accept='.md')}"></div>
|
||||
<button type="submit" id="submitBtn" class="btn btn-primary" th:text="#{MarkdownToPDF.submit}"></button>
|
||||
</form>
|
||||
<p class="mt-3" th:text="#{MarkdownToPDF.help}"></p>
|
||||
<p class="mt-3" th:text="#{MarkdownToPDF.credit}"></p>
|
||||
<head>
|
||||
<th:block th:insert="~{fragments/common :: head(title=#{MarkdownToPDF.title}, header=#{MarkdownToPDF.header})}">
|
||||
</th:block>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<th:block th:insert="~{fragments/common :: game}"></th:block>
|
||||
<div id="page-container">
|
||||
<div id="content-wrap">
|
||||
<th:block th:insert="~{fragments/navbar.html :: navbar}"></th:block>
|
||||
<br><br>
|
||||
<div class="container">
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-md-6 bg-card">
|
||||
<div class="tool-header">
|
||||
<span class="material-symbols-rounded tool-header-icon convertto">markdown</span>
|
||||
<span class="tool-header-text" th:text="#{MarkdownToPDF.header}"></span>
|
||||
</div>
|
||||
<form method="post" enctype="multipart/form-data" th:action="@{'/api/v1/convert/markdown/pdf'}">
|
||||
<div
|
||||
th:replace="~{fragments/common :: fileSelector(name='fileInput', multipleInputsForSingleRequest=false, accept='.md')}">
|
||||
</div>
|
||||
<button type="submit" id="submitBtn" class="btn btn-primary" th:text="#{MarkdownToPDF.submit}"></button>
|
||||
</form>
|
||||
<p class="mt-3" th:text="#{MarkdownToPDF.help}"></p>
|
||||
<p class="mt-3" th:text="#{MarkdownToPDF.credit}"></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<th:block th:insert="~{fragments/footer.html :: footer}"></th:block>
|
||||
</div>
|
||||
</body>
|
||||
<th:block th:insert="~{fragments/footer.html :: footer}"></th:block>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
</html>
|
@ -1,70 +1,76 @@
|
||||
<!DOCTYPE html>
|
||||
<html th:lang="${#locale.language}" th:dir="#{language.direction}" th:data-language="${#locale.toString()}" xmlns:th="https://www.thymeleaf.org">
|
||||
<head>
|
||||
<html th:lang="${#locale.language}" th:dir="#{language.direction}" th:data-language="${#locale.toString()}"
|
||||
xmlns:th="https://www.thymeleaf.org">
|
||||
|
||||
<head>
|
||||
<th:block th:insert="~{fragments/common :: head(title=#{pdfToImage.title}, header=#{pdfToImage.header})}"></th:block>
|
||||
</head>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<th:block th:insert="~{fragments/common :: game}"></th:block>
|
||||
<div id="page-container">
|
||||
<div id="content-wrap">
|
||||
<th:block th:insert="~{fragments/navbar.html :: navbar}"></th:block>
|
||||
<br><br>
|
||||
<div class="container">
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-md-6 bg-card">
|
||||
<div class="tool-header">
|
||||
<span class="material-symbols-rounded tool-header-icon image">image</span>
|
||||
<span class="tool-header-text" th:text="#{pdfToImage.header}"></span>
|
||||
</div>
|
||||
<p th:text="#{processTimeWarning}"></p>
|
||||
<p th:if="${!isPython}" th:text="#{pdfToImage.info}">Python is not installed. Required for WebP conversion.</p>
|
||||
<form method="post" enctype="multipart/form-data" th:action="@{'/api/v1/convert/pdf/img'}">
|
||||
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multipleInputsForSingleRequest=false, accept='application/pdf')}"></div>
|
||||
<div class="mb-3">
|
||||
<label th:text="#{pdfToImage.selectText}"></label>
|
||||
<select class="form-control" name="imageFormat">
|
||||
<option value="png">PNG</option>
|
||||
<option value="jpg">JPG</option>
|
||||
<option value="gif">GIF</option>
|
||||
<option value="tiff">TIFF</option>
|
||||
<option value="bmp">BMP</option>
|
||||
<option th:if="${isPython}" value="webp">WEBP</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label th:text="#{pdfToImage.singleOrMultiple}"></label>
|
||||
<select class="form-control" name="singleOrMultiple">
|
||||
<option value="multiple" th:text="#{pdfToImage.multi}"></option>
|
||||
<option value="single" th:text="#{pdfToImage.single}"></option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="mb-3" id="singleOptionSection" >
|
||||
<label for="pageNumbers" th:text="#{pageSelectionPrompt}"></label>
|
||||
<input type="text" name="pageNumbers" class="form-control" id="pageNumbers" value="all"
|
||||
th:placeholder="#{pdfToImage.placeholder}" required>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label th:text="#{pdfToImage.colorType}"></label>
|
||||
<select class="form-control" name="colorType">
|
||||
<option value="color" th:text="#{pdfToImage.color}"></option>
|
||||
<option value="greyscale" th:text="#{pdfToImage.grey}"></option>
|
||||
<option value="blackwhite" th:text="#{pdfToImage.blackwhite}"></option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="dpi">DPI:</label>
|
||||
<input type="number" name="dpi" class="form-control" id="dpi" min="1" step="1" value="300" required>
|
||||
</div>
|
||||
<button type="submit" id="submitBtn" class="btn btn-primary" th:text="#{pdfToImage.submit}"></button>
|
||||
</form>
|
||||
<body>
|
||||
<th:block th:insert="~{fragments/common :: game}"></th:block>
|
||||
<div id="page-container">
|
||||
<div id="content-wrap">
|
||||
<th:block th:insert="~{fragments/navbar.html :: navbar}"></th:block>
|
||||
<br><br>
|
||||
<div class="container">
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-md-6 bg-card">
|
||||
<div class="tool-header">
|
||||
<span class="material-symbols-rounded tool-header-icon convert">photo_library</span>
|
||||
<span class="tool-header-text" th:text="#{pdfToImage.header}"></span>
|
||||
</div>
|
||||
<p th:text="#{processTimeWarning}"></p>
|
||||
<p th:if="${!isPython}" th:text="#{pdfToImage.info}">Python is not installed. Required for WebP conversion.
|
||||
</p>
|
||||
<form method="post" enctype="multipart/form-data" th:action="@{'/api/v1/convert/pdf/img'}">
|
||||
<div
|
||||
th:replace="~{fragments/common :: fileSelector(name='fileInput', multipleInputsForSingleRequest=false, accept='application/pdf')}">
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label th:text="#{pdfToImage.selectText}"></label>
|
||||
<select class="form-control" name="imageFormat">
|
||||
<option value="png">PNG</option>
|
||||
<option value="jpg">JPG</option>
|
||||
<option value="gif">GIF</option>
|
||||
<option value="tiff">TIFF</option>
|
||||
<option value="bmp">BMP</option>
|
||||
<option th:if="${isPython}" value="webp">WEBP</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label th:text="#{pdfToImage.singleOrMultiple}"></label>
|
||||
<select class="form-control" name="singleOrMultiple">
|
||||
<option value="multiple" th:text="#{pdfToImage.multi}"></option>
|
||||
<option value="single" th:text="#{pdfToImage.single}"></option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="mb-3" id="singleOptionSection">
|
||||
<label for="pageNumbers" th:text="#{pageSelectionPrompt}"></label>
|
||||
<input type="text" name="pageNumbers" class="form-control" id="pageNumbers" value="all"
|
||||
th:placeholder="#{pdfToImage.placeholder}" required>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label th:text="#{pdfToImage.colorType}"></label>
|
||||
<select class="form-control" name="colorType">
|
||||
<option value="color" th:text="#{pdfToImage.color}"></option>
|
||||
<option value="greyscale" th:text="#{pdfToImage.grey}"></option>
|
||||
<option value="blackwhite" th:text="#{pdfToImage.blackwhite}"></option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="dpi">DPI:</label>
|
||||
<input type="number" name="dpi" class="form-control" id="dpi" min="1" step="1" value="300" required>
|
||||
</div>
|
||||
<button type="submit" id="submitBtn" class="btn btn-primary" th:text="#{pdfToImage.submit}"></button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<th:block th:insert="~{fragments/footer.html :: footer}"></th:block>
|
||||
</div>
|
||||
<th:block th:insert="~{fragments/footer.html :: footer}"></th:block>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
|
||||
</body>
|
||||
</html>
|
@ -1,41 +1,49 @@
|
||||
<!DOCTYPE html>
|
||||
<html th:lang="${#locale.language}" th:dir="#{language.direction}" th:data-language="${#locale.toString()}" xmlns:th="https://www.thymeleaf.org">
|
||||
<head>
|
||||
<th:block th:insert="~{fragments/common :: head(title=#{PDFToPresentation.title}, header=#{PDFToPresentation.header})}"></th:block>
|
||||
</head>
|
||||
<html th:lang="${#locale.language}" th:dir="#{language.direction}" th:data-language="${#locale.toString()}"
|
||||
xmlns:th="https://www.thymeleaf.org">
|
||||
|
||||
<body>
|
||||
<th:block th:insert="~{fragments/common :: game}"></th:block>
|
||||
<div id="page-container">
|
||||
<div id="content-wrap">
|
||||
<th:block th:insert="~{fragments/navbar.html :: navbar}"></th:block>
|
||||
<br><br>
|
||||
<div class="container">
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-md-6 bg-card">
|
||||
<div class="tool-header">
|
||||
<span class="material-symbols-rounded tool-header-icon ppt">slideshow</span>
|
||||
<span class="tool-header-text" th:text="#{PDFToPresentation.header}"></span>
|
||||
</div>
|
||||
<form method="post" enctype="multipart/form-data" th:action="@{'/api/v1/convert/pdf/presentation'}">
|
||||
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multipleInputsForSingleRequest=false, accept='application/pdf')}"></div>
|
||||
<div class="mb-3">
|
||||
<label th:text="#{PDFToPresentation.selectText.1}"></label>
|
||||
<select class="form-control" name="outputFormat">
|
||||
<option value="pptx">PPTX</option>
|
||||
<option value="ppt">PPT</option>
|
||||
<option value="odp">ODP</option>
|
||||
</select>
|
||||
</div>
|
||||
<br>
|
||||
<button type="submit" id="submitBtn" class="btn btn-primary" th:text="#{PDFToPresentation.submit}"></button>
|
||||
</form>
|
||||
<p class="mt-3" th:text="#{PDFToPresentation.credit}"></p>
|
||||
<head>
|
||||
<th:block
|
||||
th:insert="~{fragments/common :: head(title=#{PDFToPresentation.title}, header=#{PDFToPresentation.header})}">
|
||||
</th:block>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<th:block th:insert="~{fragments/common :: game}"></th:block>
|
||||
<div id="page-container">
|
||||
<div id="content-wrap">
|
||||
<th:block th:insert="~{fragments/navbar.html :: navbar}"></th:block>
|
||||
<br><br>
|
||||
<div class="container">
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-md-6 bg-card">
|
||||
<div class="tool-header">
|
||||
<span class="material-symbols-rounded tool-header-icon convert">slideshow</span>
|
||||
<span class="tool-header-text" th:text="#{PDFToPresentation.header}"></span>
|
||||
</div>
|
||||
<form method="post" enctype="multipart/form-data" th:action="@{'/api/v1/convert/pdf/presentation'}">
|
||||
<div
|
||||
th:replace="~{fragments/common :: fileSelector(name='fileInput', multipleInputsForSingleRequest=false, accept='application/pdf')}">
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label th:text="#{PDFToPresentation.selectText.1}"></label>
|
||||
<select class="form-control" name="outputFormat">
|
||||
<option value="pptx">PPTX</option>
|
||||
<option value="ppt">PPT</option>
|
||||
<option value="odp">ODP</option>
|
||||
</select>
|
||||
</div>
|
||||
<br>
|
||||
<button type="submit" id="submitBtn" class="btn btn-primary"
|
||||
th:text="#{PDFToPresentation.submit}"></button>
|
||||
</form>
|
||||
<p class="mt-3" th:text="#{PDFToPresentation.credit}"></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<th:block th:insert="~{fragments/footer.html :: footer}"></th:block>
|
||||
</div>
|
||||
</body>
|
||||
<th:block th:insert="~{fragments/footer.html :: footer}"></th:block>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
</html>
|
@ -1,41 +1,46 @@
|
||||
<!DOCTYPE html>
|
||||
<html th:lang="${#locale.language}" th:dir="#{language.direction}" th:data-language="${#locale.toString()}" xmlns:th="https://www.thymeleaf.org">
|
||||
<head>
|
||||
<th:block th:insert="~{fragments/common :: head(title=#{PDFToWord.title}, header=#{PDFToWord.header})}"></th:block>
|
||||
</head>
|
||||
<html th:lang="${#locale.language}" th:dir="#{language.direction}" th:data-language="${#locale.toString()}"
|
||||
xmlns:th="https://www.thymeleaf.org">
|
||||
|
||||
<body>
|
||||
<th:block th:insert="~{fragments/common :: game}"></th:block>
|
||||
<div id="page-container">
|
||||
<div id="content-wrap">
|
||||
<th:block th:insert="~{fragments/navbar.html :: navbar}"></th:block>
|
||||
<br><br>
|
||||
<div class="container">
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-md-6 bg-card">
|
||||
<div class="tool-header">
|
||||
<span class="material-symbols-rounded tool-header-icon word">description</span>
|
||||
<span class="tool-header-text" th:text="#{PDFToWord.header}"></span>
|
||||
</div>
|
||||
<form method="post" enctype="multipart/form-data" th:action="@{'/api/v1/convert/pdf/word'}">
|
||||
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multipleInputsForSingleRequest=false, accept='application/pdf')}"></div>
|
||||
<div class="mb-3">
|
||||
<label th:text="#{PDFToWord.selectText.1}"></label>
|
||||
<select class="form-control" name="outputFormat">
|
||||
<option value="docx">DocX</option>
|
||||
<option value="doc">Doc</option>
|
||||
<option value="odt">Odt</option>
|
||||
</select>
|
||||
</div>
|
||||
<br>
|
||||
<button type="submit" id="submitBtn" class="btn btn-primary" th:text="#{PDFToWord.submit}"></button>
|
||||
</form>
|
||||
<p class="mt-3" th:text="#{PDFToWord.credit}"></p>
|
||||
<head>
|
||||
<th:block th:insert="~{fragments/common :: head(title=#{PDFToWord.title}, header=#{PDFToWord.header})}"></th:block>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<th:block th:insert="~{fragments/common :: game}"></th:block>
|
||||
<div id="page-container">
|
||||
<div id="content-wrap">
|
||||
<th:block th:insert="~{fragments/navbar.html :: navbar}"></th:block>
|
||||
<br><br>
|
||||
<div class="container">
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-md-6 bg-card">
|
||||
<div class="tool-header">
|
||||
<span class="material-symbols-rounded tool-header-icon convert">description</span>
|
||||
<span class="tool-header-text" th:text="#{PDFToWord.header}"></span>
|
||||
</div>
|
||||
<form method="post" enctype="multipart/form-data" th:action="@{'/api/v1/convert/pdf/word'}">
|
||||
<div
|
||||
th:replace="~{fragments/common :: fileSelector(name='fileInput', multipleInputsForSingleRequest=false, accept='application/pdf')}">
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label th:text="#{PDFToWord.selectText.1}"></label>
|
||||
<select class="form-control" name="outputFormat">
|
||||
<option value="docx">DocX</option>
|
||||
<option value="doc">Doc</option>
|
||||
<option value="odt">Odt</option>
|
||||
</select>
|
||||
</div>
|
||||
<br>
|
||||
<button type="submit" id="submitBtn" class="btn btn-primary" th:text="#{PDFToWord.submit}"></button>
|
||||
</form>
|
||||
<p class="mt-3" th:text="#{PDFToWord.credit}"></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<th:block th:insert="~{fragments/footer.html :: footer}"></th:block>
|
||||
</div>
|
||||
</body>
|
||||
<th:block th:insert="~{fragments/footer.html :: footer}"></th:block>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
</html>
|
@ -1,33 +1,36 @@
|
||||
<!DOCTYPE html>
|
||||
<html th:lang="${#locale.language}" th:dir="#{language.direction}" th:data-language="${#locale.toString()}" xmlns:th="https://www.thymeleaf.org">
|
||||
<head>
|
||||
<th:block th:insert="~{fragments/common :: head(title=#{URLToPDF.title}, header=#{URLToPDF.header})}"></th:block>
|
||||
</head>
|
||||
<html th:lang="${#locale.language}" th:dir="#{language.direction}" th:data-language="${#locale.toString()}"
|
||||
xmlns:th="https://www.thymeleaf.org">
|
||||
|
||||
<body>
|
||||
<th:block th:insert="~{fragments/common :: game}"></th:block>
|
||||
<div id="page-container">
|
||||
<div id="content-wrap">
|
||||
<th:block th:insert="~{fragments/navbar.html :: navbar}"></th:block>
|
||||
<br><br>
|
||||
<div class="container">
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-md-6 bg-card">
|
||||
<div class="tool-header">
|
||||
<span class="material-symbols-rounded tool-header-icon convert">link</span>
|
||||
<span class="tool-header-text" th:text="#{URLToPDF.header}"></span>
|
||||
</div>
|
||||
<form method="post" enctype="multipart/form-data" th:action="@{'/api/v1/convert/url/pdf'}">
|
||||
<input type="text" class="form-control" id="urlInput" name="urlInput" placeholder="http://">
|
||||
<br>
|
||||
<button type="submit" id="submitBtn" class="btn btn-primary" th:text="#{URLToPDF.submit}"></button>
|
||||
</form>
|
||||
<p class="mt-3" th:text="#{URLToPDF.credit}"></p>
|
||||
<head>
|
||||
<th:block th:insert="~{fragments/common :: head(title=#{URLToPDF.title}, header=#{URLToPDF.header})}"></th:block>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<th:block th:insert="~{fragments/common :: game}"></th:block>
|
||||
<div id="page-container">
|
||||
<div id="content-wrap">
|
||||
<th:block th:insert="~{fragments/navbar.html :: navbar}"></th:block>
|
||||
<br><br>
|
||||
<div class="container">
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-md-6 bg-card">
|
||||
<div class="tool-header">
|
||||
<span class="material-symbols-rounded tool-header-icon convertto">link</span>
|
||||
<span class="tool-header-text" th:text="#{URLToPDF.header}"></span>
|
||||
</div>
|
||||
<form method="post" enctype="multipart/form-data" th:action="@{'/api/v1/convert/url/pdf'}">
|
||||
<input type="text" class="form-control" id="urlInput" name="urlInput" placeholder="http://">
|
||||
<br>
|
||||
<button type="submit" id="submitBtn" class="btn btn-primary" th:text="#{URLToPDF.submit}"></button>
|
||||
</form>
|
||||
<p class="mt-3" th:text="#{URLToPDF.credit}"></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<th:block th:insert="~{fragments/footer.html :: footer}"></th:block>
|
||||
</div>
|
||||
</body>
|
||||
<th:block th:insert="~{fragments/footer.html :: footer}"></th:block>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
</html>
|
@ -1,5 +1,6 @@
|
||||
<div th:fragment="card" class="feature-card hidden" th:id="${id}" th:if="${@endpointConfiguration.isEndpointEnabled(cardLink)}"
|
||||
th:data-bs-tags="${tags}">
|
||||
<div th:fragment="card" class="feature-card hidden" th:id="${id}" th:if="${@endpointConfiguration.isEndpointEnabled(cardLink)} "
|
||||
th:data-bs-tags="${tags}"
|
||||
th:data-bs-link="@{${endpoint}}">
|
||||
<a th:href="${cardLink}">
|
||||
<div class="d-flex align-items-center">
|
||||
|
||||
@ -14,10 +15,7 @@
|
||||
|
||||
</div>
|
||||
</a>
|
||||
<div class="favorite-icon" onclick="toggleFavorite(this)">
|
||||
<span class="material-symbols-rounded">
|
||||
<span class="material-symbols-rounded favorite-icon" th:data-endpoint="@{${endpoint}}" th:onclick="'addToFavorites(\'' + @{${cardLink}} + '\')'">
|
||||
star
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -1,242 +1,249 @@
|
||||
<th:block th:fragment="head">
|
||||
<!-- Title -->
|
||||
<title th:text="${@appName} + (${title} != null and ${title} != '' ? ' - ' + ${title} : '')"></title>
|
||||
<!-- Title -->
|
||||
<title th:text="${@appName} + (${title} != null and ${title} != '' ? ' - ' + ${title} : '')"></title>
|
||||
|
||||
<!-- Metadata -->
|
||||
<meta charset="utf-8">
|
||||
<meta name="description" th:content="${@appName} + (${header} != null and ${header} != '' ? ' - ' + ${header} : '')">
|
||||
<meta name="msapplication-TileColor" content="#2d89ef">
|
||||
<meta name="theme-color" content="#ffffff">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<!-- Metadata -->
|
||||
<meta charset="utf-8">
|
||||
<meta name="description" th:content="${@appName} + (${header} != null and ${header} != '' ? ' - ' + ${header} : '')">
|
||||
<meta name="msapplication-TileColor" content="#2d89ef">
|
||||
<meta name="theme-color" content="#ffffff">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
|
||||
<!-- Icons -->
|
||||
<link rel="apple-touch-icon" sizes="180x180" th:href="@{'/apple-touch-icon.png'}">
|
||||
<link rel="icon" type="image/png" sizes="32x32" th:href="@{'/favicon-32x32.png'}">
|
||||
<link rel="icon" type="image/png" sizes="16x16" th:href="@{'/favicon-16x16.png'}">
|
||||
<link rel="manifest" th:href="@{'/site.webmanifest'}" crossorigin="use-credentials">
|
||||
<link rel="mask-icon" th:href="@{'/safari-pinned-tab.svg'}" color="#ca2b2a">
|
||||
<link rel="shortcut icon" th:href="@{'/favicon.ico'}">
|
||||
<meta name="apple-mobile-web-app-title" content="Stirling PDF">
|
||||
<meta name="application-name" content="Stirling PDF">
|
||||
<meta name="msapplication-TileColor" content="#00aba9">
|
||||
<meta name="theme-color" content="#ffffff">
|
||||
<!-- Icons -->
|
||||
<link rel="apple-touch-icon" sizes="180x180" th:href="@{'/apple-touch-icon.png'}">
|
||||
<link rel="icon" type="image/png" sizes="32x32" th:href="@{'/favicon-32x32.png'}">
|
||||
<link rel="icon" type="image/png" sizes="16x16" th:href="@{'/favicon-16x16.png'}">
|
||||
<link rel="manifest" th:href="@{'/site.webmanifest'}" crossorigin="use-credentials">
|
||||
<link rel="mask-icon" th:href="@{'/safari-pinned-tab.svg'}" color="#ca2b2a">
|
||||
<link rel="shortcut icon" th:href="@{'/favicon.ico'}">
|
||||
<meta name="apple-mobile-web-app-title" content="Stirling PDF">
|
||||
<meta name="application-name" content="Stirling PDF">
|
||||
<meta name="msapplication-TileColor" content="#00aba9">
|
||||
<meta name="theme-color" content="#ffffff">
|
||||
|
||||
<script>
|
||||
window.stirlingPDF = window.stirlingPDF || {};
|
||||
</script>
|
||||
<script th:src="@{'/js/thirdParty/pdf-lib.min.js'}"></script>
|
||||
<script th:src="@{'/js/fetch-utils.js'}"></script>
|
||||
<!-- jQuery -->
|
||||
<script th:src="@{'/js/thirdParty/jquery.min.js'}"></script>
|
||||
<script th:src="@{'/js/thirdParty/jquery.validate.min.js'}"></script>
|
||||
<script th:src="@{'/js/thirdParty/jszip.min.js'}" th:if="${currentPage != 'home'}"></script>
|
||||
<script>
|
||||
window.stirlingPDF = window.stirlingPDF || {};
|
||||
</script>
|
||||
<script th:src="@{'/js/thirdParty/pdf-lib.min.js'}"></script>
|
||||
<script th:src="@{'/js/fetch-utils.js'}"></script>
|
||||
<!-- jQuery -->
|
||||
<script th:src="@{'/js/thirdParty/jquery.min.js'}"></script>
|
||||
<script th:src="@{'/js/thirdParty/jquery.validate.min.js'}"></script>
|
||||
<script th:src="@{'/js/thirdParty/jszip.min.js'}" th:if="${currentPage != 'home'}"></script>
|
||||
|
||||
<!-- Bootstrap -->
|
||||
<script th:src="@{'/js/thirdParty/popper.min.js'}"></script>
|
||||
<script th:src="@{'/js/thirdParty/bootstrap.min.js'}"></script>
|
||||
<link rel="stylesheet" th:href="@{'/css/bootstrap.min.css'}">
|
||||
<!-- Bootstrap -->
|
||||
<script th:src="@{'/js/thirdParty/popper.min.js'}"></script>
|
||||
<script th:src="@{'/js/thirdParty/bootstrap.min.js'}"></script>
|
||||
<link rel="stylesheet" th:href="@{'/css/bootstrap.min.css'}">
|
||||
|
||||
<!-- Bootstrap Icons -->
|
||||
<link rel="stylesheet" th:href="@{'/css/bootstrap-icons.min.css'}">
|
||||
<!-- Bootstrap Icons -->
|
||||
<link rel="stylesheet" th:href="@{'/css/bootstrap-icons.min.css'}">
|
||||
|
||||
<!-- Custom -->
|
||||
<link rel="stylesheet" th:href="@{'/css/general.css'}">
|
||||
<link rel="stylesheet" th:href="@{'/css/theme/theme.css'}">
|
||||
<link rel="stylesheet" th:href="@{'/css/theme/componentes.css'}">
|
||||
<link rel="stylesheet" th:href="@{'/css/theme/theme.light.css'}" id="light-mode-styles">
|
||||
<link rel="stylesheet" th:href="@{'/css/theme/theme.dark.css'}" id="dark-mode-styles">
|
||||
<link rel="stylesheet" th:href="@{'/css/rainbow-mode.css'}" id="rainbow-mode-styles" disabled>
|
||||
<link rel="stylesheet" th:href="@{'/css/tab-container.css'}">
|
||||
<link rel="stylesheet" th:href="@{'/css/navbar.css'}">
|
||||
<!-- Custom -->
|
||||
<link rel="stylesheet" th:href="@{'/css/general.css'}">
|
||||
<link rel="stylesheet" th:href="@{'/css/theme/theme.css'}">
|
||||
<link rel="stylesheet" th:href="@{'/css/theme/componentes.css'}">
|
||||
<link rel="stylesheet" th:href="@{'/css/theme/theme.light.css'}" id="light-mode-styles">
|
||||
<link rel="stylesheet" th:href="@{'/css/theme/theme.dark.css'}" id="dark-mode-styles">
|
||||
<link rel="stylesheet" th:href="@{'/css/rainbow-mode.css'}" id="rainbow-mode-styles" disabled>
|
||||
<link rel="stylesheet" th:href="@{'/css/tab-container.css'}">
|
||||
<link rel="stylesheet" th:href="@{'/css/navbar.css'}">
|
||||
|
||||
<link rel="stylesheet" th:href="@{'/css/error.css'}" th:if="${error}">
|
||||
<link rel="stylesheet" th:href="@{'/css/error.css'}" th:if="${error}">
|
||||
|
||||
<link rel="stylesheet" th:href="@{'/css/home.css'}" th:if="${currentPage == 'home'}">
|
||||
<link rel="stylesheet" th:href="@{'/css/account.css'}" th:if="${currentPage == 'account'}">
|
||||
<link rel="stylesheet" th:href="@{'/css/licenses.css'}" th:if="${currentPage == 'licenses'}">
|
||||
<link rel="stylesheet" th:href="@{'/css/multi-tool.css'}" th:if="${currentPage == 'multi-tool'}">
|
||||
<link rel="stylesheet" th:href="@{'/css/rotate-pdf.css'}" th:if="${currentPage == 'rotate-pdf'}">
|
||||
<link rel="stylesheet" th:href="@{'/css/stamp.css'}" th:if="${currentPage == 'stamp'}">
|
||||
<link rel="stylesheet" th:href="@{'/css/fileSelect.css'}" th:if="${currentPage != 'home'}">
|
||||
<link rel="stylesheet" th:href="@{'/css/footer.css'}">
|
||||
<link rel="stylesheet" th:href="@{'/css/home.css'}" th:if="${currentPage == 'home'}">
|
||||
<link rel="stylesheet" th:href="@{'/css/home-legacy.css'}" th:if="${currentPage == 'home-legacy'}">
|
||||
<link rel="stylesheet" th:href="@{'/css/account.css'}" th:if="${currentPage == 'account'}">
|
||||
<link rel="stylesheet" th:href="@{'/css/licenses.css'}" th:if="${currentPage == 'licenses'}">
|
||||
<link rel="stylesheet" th:href="@{'/css/multi-tool.css'}" th:if="${currentPage == 'multi-tool'}">
|
||||
<link rel="stylesheet" th:href="@{'/css/rotate-pdf.css'}" th:if="${currentPage == 'rotate-pdf'}">
|
||||
<link rel="stylesheet" th:href="@{'/css/stamp.css'}" th:if="${currentPage == 'stamp'}">
|
||||
<link rel="stylesheet" th:href="@{'/css/fileSelect.css'}" th:if="${currentPage != 'home'}">
|
||||
<link rel="stylesheet" th:href="@{'/css/footer.css'}">
|
||||
|
||||
<link rel="preload" th:href="@{'/fonts/google-symbol.woff2'}" as="font" type="font/woff2" crossorigin="anonymous">
|
||||
<link rel="preload" th:href="@{'/fonts/google-symbol.woff2'}" as="font" type="font/woff2" crossorigin="anonymous">
|
||||
|
||||
<script th:src="@{'/js/thirdParty/fontfaceobserver.standalone.js'}"></script>
|
||||
<script th:src="@{'/js/thirdParty/fontfaceobserver.standalone.js'}"></script>
|
||||
|
||||
<!-- Google MD Icons -->
|
||||
<link rel="stylesheet" th:href="@{'/css/theme/font.css'}">
|
||||
<!-- Google MD Icons -->
|
||||
<link rel="stylesheet" th:href="@{'/css/theme/font.css'}">
|
||||
|
||||
<!-- Help Modal -->
|
||||
<link rel="stylesheet" th:href="@{'/css/errorBanner.css'}" th:if="${currentPage != 'home'}">
|
||||
<!-- Help Modal -->
|
||||
<link rel="stylesheet" th:href="@{'/css/errorBanner.css'}" th:if="${currentPage != 'home'}">
|
||||
|
||||
<script th:src="@{'/js/cacheFormInputs.js'}" th:if="${currentPage != 'home'}"></script>
|
||||
<script th:src="@{'/js/tab-container.js'}"></script>
|
||||
<script th:src="@{'/js/darkmode.js'}"></script>
|
||||
<script th:src="@{'/js/csrf.js'}"></script>
|
||||
<script th:inline="javascript">
|
||||
const stirlingPDFLabel = /*[[${@StirlingPDFLabel}]]*/ '';
|
||||
const analyticsEnabled = /*[[${@analyticsEnabled}]]*/ false;
|
||||
<script th:src="@{'/js/cacheFormInputs.js'}" th:if="${currentPage != 'home'}"></script>
|
||||
<script th:src="@{'/js/tab-container.js'}"></script>
|
||||
<script th:src="@{'/js/darkmode.js'}"></script>
|
||||
<script th:src="@{'/js/csrf.js'}"></script>
|
||||
<script th:inline="javascript">
|
||||
const stirlingPDFLabel = /*[[${@StirlingPDFLabel}]]*/ '';
|
||||
const analyticsEnabled = /*[[${@analyticsEnabled}]]*/ false;
|
||||
|
||||
if (analyticsEnabled) {
|
||||
!function (t, e) {
|
||||
var o, n, p, r;
|
||||
e.__SV || (window.posthog = e, e._i = [], e.init = function (i, s, a) {
|
||||
function g(t, e) {
|
||||
var o = e.split(".");
|
||||
2 == o.length && (t = t[o[0]], e = o[1]), t[e] = function () {
|
||||
t.push([e].concat(Array.prototype.slice.call(arguments, 0)))
|
||||
}
|
||||
}
|
||||
if (analyticsEnabled) {
|
||||
!function (t, e) {
|
||||
var o, n, p, r;
|
||||
e.__SV || (window.posthog = e, e._i = [], e.init = function (i, s, a) {
|
||||
function g(t, e) {
|
||||
var o = e.split(".");
|
||||
2 == o.length && (t = t[o[0]], e = o[1]), t[e] = function () {
|
||||
t.push([e].concat(Array.prototype.slice.call(arguments, 0)))
|
||||
}
|
||||
}
|
||||
|
||||
(p = t.createElement("script")).type = "text/javascript", p.async = !0, p.src = s.api_host + "/static/array.js", (r = t.getElementsByTagName("script")[0]).parentNode.insertBefore(p, r);
|
||||
var u = e;
|
||||
for (void 0 !== a ? u = e[a] = [] : a = "posthog", u.people = u.people || [], u.toString = function (t) {
|
||||
var e = "posthog";
|
||||
return "posthog" !== a && (e += "." + a), t || (e += " (stub)"), e
|
||||
}, u.people.toString = function () {
|
||||
return u.toString(1) + ".people (stub)"
|
||||
}, o = "capture identify alias people.set people.set_once set_config register register_once unregister opt_out_capturing has_opted_out_capturing opt_in_capturing reset isFeatureEnabled onFeatureFlags getFeatureFlag getFeatureFlagPayload reloadFeatureFlags group updateEarlyAccessFeatureEnrollment getEarlyAccessFeatures getActiveMatchingSurveys getSurveys getNextSurveyStep onSessionId".split(" "), n = 0; n < o.length; n++) g(u, o[n]);
|
||||
e._i.push([i, s, a])
|
||||
}, e.__SV = 1)
|
||||
}(document, window.posthog || []);
|
||||
posthog.init('phc_fiR65u5j6qmXTYL56MNrLZSWqLaDW74OrZH0Insd2xq', {
|
||||
api_host: 'https://eu.i.posthog.com',
|
||||
persistence: 'localStorage',
|
||||
person_profiles: 'always',
|
||||
mask_all_text: true,
|
||||
mask_all_element_attributes: true
|
||||
})
|
||||
const baseUrl = window.location.hostname;
|
||||
posthog.register_once({
|
||||
'hostname': baseUrl,
|
||||
'UUID': /*[[${@UUID}]]*/ ''
|
||||
})
|
||||
}
|
||||
</script>
|
||||
(p = t.createElement("script")).type = "text/javascript", p.async = !0, p.src = s.api_host + "/static/array.js", (r = t.getElementsByTagName("script")[0]).parentNode.insertBefore(p, r);
|
||||
var u = e;
|
||||
for (void 0 !== a ? u = e[a] = [] : a = "posthog", u.people = u.people || [], u.toString = function (t) {
|
||||
var e = "posthog";
|
||||
return "posthog" !== a && (e += "." + a), t || (e += " (stub)"), e
|
||||
}, u.people.toString = function () {
|
||||
return u.toString(1) + ".people (stub)"
|
||||
}, o = "capture identify alias people.set people.set_once set_config register register_once unregister opt_out_capturing has_opted_out_capturing opt_in_capturing reset isFeatureEnabled onFeatureFlags getFeatureFlag getFeatureFlagPayload reloadFeatureFlags group updateEarlyAccessFeatureEnrollment getEarlyAccessFeatures getActiveMatchingSurveys getSurveys getNextSurveyStep onSessionId".split(" "), n = 0; n < o.length; n++) g(u, o[n]);
|
||||
e._i.push([i, s, a])
|
||||
}, e.__SV = 1)
|
||||
}(document, window.posthog || []);
|
||||
posthog.init('phc_fiR65u5j6qmXTYL56MNrLZSWqLaDW74OrZH0Insd2xq', {
|
||||
api_host: 'https://eu.i.posthog.com',
|
||||
persistence: 'localStorage',
|
||||
person_profiles: 'always',
|
||||
mask_all_text: true,
|
||||
mask_all_element_attributes: true
|
||||
})
|
||||
const baseUrl = window.location.hostname;
|
||||
posthog.register_once({
|
||||
'hostname': baseUrl,
|
||||
'UUID': /*[[${@UUID}]]*/ ''
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
|
||||
</th:block>
|
||||
</th:block>
|
||||
|
||||
<th:block th:fragment="game">
|
||||
<dialog id="game-container-wrapper" class="game-container-wrapper" data-bs-modal>
|
||||
<script th:inline="javascript">
|
||||
console.log("loaded game");
|
||||
$(document).ready(function() {
|
||||
<dialog id="game-container-wrapper" class="game-container-wrapper" data-bs-modal>
|
||||
<script th:inline="javascript">
|
||||
console.log("loaded game");
|
||||
$(document).ready(function () {
|
||||
|
||||
// Find the file input within the form
|
||||
var fileInput = $('input[type="file"]');
|
||||
// Find the file input within the form
|
||||
var fileInput = $('input[type="file"]');
|
||||
|
||||
// Find the closest enclosing form of the file input
|
||||
var form = fileInput.closest('form');
|
||||
// Find the closest enclosing form of the file input
|
||||
var form = fileInput.closest('form');
|
||||
|
||||
// Find the submit button within the form
|
||||
var submitButton = form.find('button[type="submit"], input[type="submit"]');
|
||||
// Find the submit button within the form
|
||||
var submitButton = form.find('button[type="submit"], input[type="submit"]');
|
||||
|
||||
const boredWaitingText = /*[[#{bored}]]*/ 'Bored Waiting?';
|
||||
const downloadCompleteText = /*[[#{downloadComplete}]]*/ 'Download Complete';
|
||||
window.downloadCompleteText = downloadCompleteText;
|
||||
// Create the 'show-game-btn' button
|
||||
var gameButton = $('<button type="button" class="btn btn-primary" id="show-game-btn" style="display:none;">' + boredWaitingText + '</button>');
|
||||
const boredWaitingText = /*[[#{bored}]]*/ 'Bored Waiting?';
|
||||
const downloadCompleteText = /*[[#{downloadComplete}]]*/ 'Download Complete';
|
||||
window.downloadCompleteText = downloadCompleteText;
|
||||
// Create the 'show-game-btn' button
|
||||
var gameButton = $('<button type="button" class="btn btn-primary" id="show-game-btn" style="display:none;">' + boredWaitingText + '</button>');
|
||||
|
||||
// Insert the 'show-game-btn' just above the submit button
|
||||
submitButton.before(gameButton);
|
||||
// Insert the 'show-game-btn' just above the submit button
|
||||
submitButton.before(gameButton);
|
||||
|
||||
function loadGameScript(callback) {
|
||||
console.log('loadGameScript called');
|
||||
const script = document.createElement('script');
|
||||
script.src = 'js/game.js';
|
||||
script.onload = callback;
|
||||
document.body.appendChild(script);
|
||||
function loadGameScript(callback) {
|
||||
console.log('loadGameScript called');
|
||||
const script = document.createElement('script');
|
||||
script.src = 'js/game.js';
|
||||
script.onload = callback;
|
||||
document.body.appendChild(script);
|
||||
}
|
||||
let gameScriptLoaded = false;
|
||||
const gameDialog = document.getElementById('game-container-wrapper');
|
||||
$('#show-game-btn').on('click', function () {
|
||||
console.log('Show game button clicked');
|
||||
if (!gameScriptLoaded) {
|
||||
console.log('Show game button load');
|
||||
loadGameScript(function () {
|
||||
console.log('Game script loaded');
|
||||
window.initializeGame();
|
||||
gameScriptLoaded = true;
|
||||
});
|
||||
} else {
|
||||
window.resetGame();
|
||||
}
|
||||
gameDialog.showModal();
|
||||
});
|
||||
gameDialog.addEventListener("click", e => {
|
||||
const dialogDimensions = gameDialog.getBoundingClientRect()
|
||||
if (
|
||||
e.clientX < dialogDimensions.left ||
|
||||
e.clientX > dialogDimensions.right ||
|
||||
e.clientY < dialogDimensions.top ||
|
||||
e.clientY > dialogDimensions.bottom
|
||||
) {
|
||||
gameDialog.close();
|
||||
}
|
||||
let gameScriptLoaded = false;
|
||||
const gameDialog = document.getElementById('game-container-wrapper');
|
||||
$('#show-game-btn').on('click', function() {
|
||||
console.log('Show game button clicked');
|
||||
if (!gameScriptLoaded) {
|
||||
console.log('Show game button load');
|
||||
loadGameScript(function() {
|
||||
console.log('Game script loaded');
|
||||
window.initializeGame();
|
||||
gameScriptLoaded = true;
|
||||
});
|
||||
} else {
|
||||
window.resetGame();
|
||||
}
|
||||
gameDialog.showModal();
|
||||
});
|
||||
gameDialog.addEventListener("click", e => {
|
||||
const dialogDimensions = gameDialog.getBoundingClientRect()
|
||||
if (
|
||||
e.clientX < dialogDimensions.left ||
|
||||
e.clientX > dialogDimensions.right ||
|
||||
e.clientY < dialogDimensions.top ||
|
||||
e.clientY > dialogDimensions.bottom
|
||||
) {
|
||||
gameDialog.close();
|
||||
}
|
||||
})
|
||||
})
|
||||
</script>
|
||||
<div id="game-container">
|
||||
<div id="lives">Lives: 3</div>
|
||||
<div id="score">Score: 0</div>
|
||||
<div id="high-score">High Score: 0</div>
|
||||
<div id="level">Level: 1</div>
|
||||
<img th:src="@{'/favicon.svg'}" class="player" id="player" alt="favicon">
|
||||
})
|
||||
</script>
|
||||
<div id="game-container">
|
||||
<div id="lives">Lives: 3</div>
|
||||
<div id="score">Score: 0</div>
|
||||
<div id="high-score">High Score: 0</div>
|
||||
<div id="level">Level: 1</div>
|
||||
<img th:src="@{'/favicon.svg'}" class="player" id="player" alt="favicon">
|
||||
</div>
|
||||
<link rel="stylesheet" th:href="@{'/css/game.css'}">
|
||||
</dialog>
|
||||
</th:block>
|
||||
|
||||
<th:block th:fragment="fileSelector(name, multipleInputsForSingleRequest)"
|
||||
th:with="accept=${accept} ?: '*/*', inputText=${inputText} ?: #{pdfPrompt}, remoteCall=${remoteCall} ?: true, disableMultipleFiles=${disableMultipleFiles} ?: false, notRequired=${notRequired} ?: false">
|
||||
<script th:inline="javascript">
|
||||
(function () {
|
||||
window.stirlingPDF.pdfPasswordPrompt = /*[[#{error.pdfPassword}]]*/ '';
|
||||
window.stirlingPDF.multipleInputsForSingleRequest = /*[[${multipleInputsForSingleRequest}]]*/ false;
|
||||
window.stirlingPDF.disableMultipleFiles = /*[[${disableMultipleFiles}]]*/ false;
|
||||
window.stirlingPDF.remoteCall = /*[[${remoteCall}]]*/ true;
|
||||
window.stirlingPDF.sessionExpired = /*[[#{session.expired}]]*/ '';
|
||||
window.stirlingPDF.refreshPage = /*[[#{session.refreshPage}]]*/ 'Refresh Page';
|
||||
window.stirlingPDF.error = /*[[#{error}]]*/ "Error";
|
||||
})();
|
||||
</script>
|
||||
<script type="module" th:src="@{'/pdfjs-legacy/pdf.mjs'}"></script>
|
||||
<script th:src="@{'/js/downloader.js'}"></script>
|
||||
<script>
|
||||
window.decrypt = {
|
||||
passwordPrompt: '[[#{decrypt.passwordPrompt}]]',
|
||||
cancelled: '[[#{decrypt.cancelled}]]',
|
||||
noPassword: '[[#{decrypt.noPassword}]]',
|
||||
invalidPassword: '[[#{decrypt.invalidPassword}]]',
|
||||
invalidPasswordHeader: '[[#{decrypt.invalidPasswordHeader}]]',
|
||||
unexpectedError: '[[#{decrypt.unexpectedError}]]',
|
||||
serverError: '[[#{decrypt.serverError}]]',
|
||||
success: '[[#{decrypt.success}]]',
|
||||
};
|
||||
window.fileInput = {
|
||||
dragAndDropPDF: '[[#{fileChooser.dragAndDropPDF}]]',
|
||||
dragAndDropImage: '[[#{fileChooser.dragAndDropImage}]]'
|
||||
};</script>
|
||||
<div class="custom-file-chooser mb-3"
|
||||
th:attr="data-bs-unique-id=${name}, data-bs-element-id=${name+'-input'}, data-bs-element-container-id=${name+'-input-container'}, data-bs-files-selected=#{filesSelected}, data-bs-pdf-prompt=#{pdfPrompt}">
|
||||
<div class="mb-3 d-flex flex-row justify-content-center align-items-center flex-wrap input-container"
|
||||
th:name="${name}+'-input'" th:id="${name}+'-input-container'" th:data-text="#{fileChooser.hoveredDragAndDrop}">
|
||||
<label class="file-input-btn d-none">
|
||||
<input type="file" class="form-control" th:name="${name}" th:id="${name}+'-input'" th:accept="${accept}"
|
||||
th:attr="multiple=${!disableMultipleFiles}" th:required="${notRequired} ? null : 'required'">
|
||||
Browse
|
||||
</label>
|
||||
<div th:text="#{fileChooser.click}"></div>
|
||||
<div th:text="#{fileChooser.or}"></div>
|
||||
<div th:text="#{fileChooser.dragAndDrop}" id="dragAndDrop"></div>
|
||||
</div>
|
||||
<div class="selected-files flex-wrap"></div>
|
||||
</div>
|
||||
|
||||
<div class="progressBarContainer" style="display: none; position: relative;">
|
||||
<div class="progress" style="height: 1rem;">
|
||||
<div class="progressBar progress-bar progress-bar-striped progress-bar-animated bg-success" role="progressbar"
|
||||
aria-valuenow="0" aria-valuemin="0" aria-valuemax="100" style="width: 0%;">
|
||||
<span class="visually-hidden">Loading...</span>
|
||||
</div>
|
||||
<link rel="stylesheet" th:href="@{'/css/game.css'}">
|
||||
</dialog>
|
||||
</th:block>
|
||||
|
||||
<th:block th:fragment="fileSelector(name, multipleInputsForSingleRequest)" th:with="accept=${accept} ?: '*/*', inputText=${inputText} ?: #{pdfPrompt}, remoteCall=${remoteCall} ?: true, disableMultipleFiles=${disableMultipleFiles} ?: false, notRequired=${notRequired} ?: false">
|
||||
<script th:inline="javascript">
|
||||
(function() {
|
||||
window.stirlingPDF.pdfPasswordPrompt = /*[[#{error.pdfPassword}]]*/ '';
|
||||
window.stirlingPDF.multipleInputsForSingleRequest = /*[[${multipleInputsForSingleRequest}]]*/ false;
|
||||
window.stirlingPDF.disableMultipleFiles = /*[[${disableMultipleFiles}]]*/ false;
|
||||
window.stirlingPDF.remoteCall = /*[[${remoteCall}]]*/ true;
|
||||
window.stirlingPDF.sessionExpired = /*[[#{session.expired}]]*/ '';
|
||||
window.stirlingPDF.refreshPage = /*[[#{session.refreshPage}]]*/ 'Refresh Page';
|
||||
window.stirlingPDF.error = /*[[#{error}]]*/ "Error";
|
||||
})();
|
||||
</script>
|
||||
<script type="module" th:src="@{'/pdfjs-legacy/pdf.mjs'}"></script>
|
||||
<script th:src="@{'/js/downloader.js'}"></script>
|
||||
<script>
|
||||
window.decrypt = {
|
||||
passwordPrompt: '[[#{decrypt.passwordPrompt}]]',
|
||||
cancelled: '[[#{decrypt.cancelled}]]',
|
||||
noPassword: '[[#{decrypt.noPassword}]]',
|
||||
invalidPassword: '[[#{decrypt.invalidPassword}]]',
|
||||
invalidPasswordHeader: '[[#{decrypt.invalidPasswordHeader}]]',
|
||||
unexpectedError: '[[#{decrypt.unexpectedError}]]',
|
||||
serverError: '[[#{decrypt.serverError}]]',
|
||||
success: '[[#{decrypt.success}]]',
|
||||
};
|
||||
window.fileInput = {
|
||||
dragAndDropPDF : '[[#{fileChooser.dragAndDropPDF}]]',
|
||||
dragAndDropImage : '[[#{fileChooser.dragAndDropImage}]]'};</script>
|
||||
<div class="custom-file-chooser mb-3" th:attr="data-bs-unique-id=${name}, data-bs-element-id=${name+'-input'}, data-bs-element-container-id=${name+'-input-container'}, data-bs-files-selected=#{filesSelected}, data-bs-pdf-prompt=#{pdfPrompt}">
|
||||
<div class="mb-3 d-flex flex-row justify-content-center align-items-center flex-wrap input-container" th:name="${name}+'-input'" th:id="${name}+'-input-container'" th:data-text="#{fileChooser.hoveredDragAndDrop}">
|
||||
<label class="file-input-btn d-none">
|
||||
<input type="file" class="form-control" th:name="${name}" th:id="${name}+'-input'" th:accept="${accept}" th:attr="multiple=${!disableMultipleFiles}" th:required="${notRequired} ? null : 'required'">
|
||||
Browse
|
||||
</label>
|
||||
<div th:text="#{fileChooser.click}"></div>
|
||||
<div th:text="#{fileChooser.or}"></div>
|
||||
<div th:text="#{fileChooser.dragAndDrop}" id="dragAndDrop"></div>
|
||||
</div>
|
||||
<div class="selected-files flex-wrap"></div>
|
||||
</div>
|
||||
|
||||
<div class="progressBarContainer" style="display: none; position: relative;">
|
||||
<div class="progress" style="height: 1rem;">
|
||||
<div class="progressBar progress-bar progress-bar-striped progress-bar-animated bg-success" role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100" style="width: 0%;">
|
||||
<span class="visually-hidden">Loading...</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script th:src="@{'/js/fileInput.js'}" type="module"></script>
|
||||
</th:block>
|
||||
</div>
|
||||
</div>
|
||||
<script th:src="@{'/js/fileInput.js'}" type="module"></script>
|
||||
</th:block>
|
@ -1,6 +1,3 @@
|
||||
<div th:fragment="featureGroupHeader" class="feature-group-header">
|
||||
<h3 class="menu-title" th:text="${groupTitle}"></h3>
|
||||
<span class="material-symbols-rounded header-expand-button">
|
||||
chevron_right
|
||||
</span>
|
||||
<h6 class="menu-title" th:text="${groupTitle}"></h6>
|
||||
</div>
|
@ -0,0 +1,6 @@
|
||||
<div th:fragment="featureGroupHeader" class="feature-group-header">
|
||||
<h3 class="menu-title" th:text="${groupTitle}"></h3>
|
||||
<span class="material-symbols-rounded header-expand-button">
|
||||
chevron_right
|
||||
</span>
|
||||
</div>
|
296
src/main/resources/templates/fragments/navElements.html
Normal file
296
src/main/resources/templates/fragments/navElements.html
Normal file
@ -0,0 +1,296 @@
|
||||
<th:block th:fragment="navElements">
|
||||
<div id="groupOrganize" class="feature-group">
|
||||
<div
|
||||
th:replace="~{fragments/featureGroupHeader :: featureGroupHeader(groupTitle=#{navbar.sections.organize})}">
|
||||
</div>
|
||||
<div class="nav-group-container">
|
||||
<div
|
||||
th:replace="~{fragments/navbarEntry :: navbarEntry ('multi-tool', 'construction', 'home.multiTool.title', 'home.multiTool.desc', 'multiTool.tags', 'organize')}">
|
||||
</div>
|
||||
|
||||
<div
|
||||
th:replace="~{fragments/navbarEntry :: navbarEntry ('merge-pdfs', 'add_to_photos', 'home.merge.title', 'home.merge.desc', 'merge.tags', 'organize')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/navbarEntry :: navbarEntry ('split-pdfs', 'cut', 'home.split.title', 'home.split.desc', 'split.tags', 'organize')}"></div>
|
||||
<div
|
||||
th:replace="~{fragments/navbarEntry :: navbarEntry('rotate-pdf', 'rotate_right', 'home.rotate.title', 'home.rotate.desc', 'rotate.tags', 'organize')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/navbarEntry :: navbarEntry('crop', 'crop', 'home.crop.title', 'home.crop.desc', 'crop.tags', 'organize')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/navbarEntry :: navbarEntry('pdf-organizer', 'format_list_bulleted', 'home.pdfOrganiser.title', 'home.pdfOrganiser.desc', 'pdfOrganiser.tags', 'organize')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/navbarEntry :: navbarEntry('remove-pages', 'delete', 'home.removePages.title', 'home.removePages.desc', 'removePages.tags', 'organize')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/navbarEntry :: navbarEntry('multi-page-layout', 'dashboard', 'home.pageLayout.title', 'home.pageLayout.desc', 'pageLayout.tags', 'organize')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/navbarEntry :: navbarEntry('scale-pages', 'fullscreen', 'home.scalePages.title', 'home.scalePages.desc', 'scalePages.tags', 'organize')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/navbarEntry :: navbarEntry('extract-page', 'upload', 'home.extractPage.title', 'home.extractPage.desc', 'extractPage.tags', 'organize')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/navbarEntry :: navbarEntry('pdf-to-single-page', 'looks_one', 'home.PdfToSinglePage.title', 'home.PdfToSinglePage.desc', 'PdfToSinglePage.tags', 'organize')}">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="groupConvertTo" class="feature-group">
|
||||
<div
|
||||
th:replace="~{fragments/featureGroupHeader :: featureGroupHeader(groupTitle=#{navbar.sections.convertTo})}">
|
||||
</div>
|
||||
<div class="nav-group-container">
|
||||
<div
|
||||
th:replace="~{fragments/navbarEntry :: navbarEntry('img-to-pdf', 'picture_as_pdf', 'home.imageToPdf.title', 'home.imageToPdf.desc', 'imageToPdf.tags', 'convertto')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/navbarEntry :: navbarEntry('file-to-pdf', 'draft', 'home.fileToPDF.title', 'home.fileToPDF.desc', 'fileToPDF.tags', 'convertto')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/navbarEntry :: navbarEntry('url-to-pdf', 'link', 'home.URLToPDF.title', 'home.URLToPDF.desc', 'URLToPDF.tags', 'convertto')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/navbarEntry :: navbarEntry('html-to-pdf', 'html', 'home.HTMLToPDF.title', 'home.HTMLToPDF.desc', 'HTMLToPDF.tags', 'convertto')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/navbarEntry :: navbarEntry('markdown-to-pdf', 'markdown', 'home.MarkdownToPDF.title', 'home.MarkdownToPDF.desc', 'MarkdownToPDF.tags', 'convertto')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/navbarEntry :: navbarEntry('book-to-pdf', 'book', 'home.BookToPDF.title', 'home.BookToPDF.desc', 'BookToPDF.tags', 'convertto')}">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="groupConvertFrom" class="feature-group">
|
||||
<div
|
||||
th:replace="~{fragments/featureGroupHeader :: featureGroupHeader(groupTitle=#{navbar.sections.convertFrom})}">
|
||||
</div>
|
||||
<div class="nav-group-container">
|
||||
<div
|
||||
th:replace="~{fragments/navbarEntry :: navbarEntry('pdf-to-img', 'photo_library', 'home.pdfToImage.title', 'home.pdfToImage.desc', 'pdfToImage.tags', 'convert')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/navbarEntry :: navbarEntry('pdf-to-pdfa', 'picture_as_pdf', 'home.pdfToPDFA.title', 'home.pdfToPDFA.desc', 'pdfToPDFA.tags', 'convert')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/navbarEntry :: navbarEntry('pdf-to-word', 'description', 'home.PDFToWord.title', 'home.PDFToWord.desc', 'PDFToWord.tags', 'convert')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/navbarEntry :: navbarEntry('pdf-to-presentation', 'slideshow', 'home.PDFToPresentation.title', 'home.PDFToPresentation.desc', 'PDFToPresentation.tags', 'convert')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/navbarEntry :: navbarEntry('pdf-to-text', 'text_fields', 'home.PDFToText.title', 'home.PDFToText.desc', 'PDFToText.tags', 'convert')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/navbarEntry :: navbarEntry('pdf-to-html', 'html', 'home.PDFToHTML.title', 'home.PDFToHTML.desc', 'PDFToHTML.tags', 'convert')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/navbarEntry :: navbarEntry('pdf-to-xml', 'code', 'home.PDFToXML.title', 'home.PDFToXML.desc', 'PDFToXML.tags', 'convert')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/navbarEntry :: navbarEntry('pdf-to-csv', 'csv', 'home.tableExtraxt.title', 'home.tableExtraxt.desc', 'tableExtraxt.tags', 'convert')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/navbarEntry :: navbarEntry('pdf-to-book', 'book', 'home.PDFToBook.title', 'home.PDFToBook.desc', 'PDFToBook.tags', 'convert')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/navbarEntry :: navbarEntry ('pdf-to-markdown', 'markdown_copy', 'home.PDFToMarkdown.title', 'home.PDFToMarkdown.desc', 'PDFToMarkdown.tags', 'convert')}">
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div id="convertGroup" class="feature-group">
|
||||
<div
|
||||
th:replace="~{fragments/featureGroupHeader :: featureGroupHeader(groupTitle=#{navbar.sections.convertTo})}">
|
||||
</div>
|
||||
<div class="nav-group-container">
|
||||
<div
|
||||
th:replace="~{fragments/navbarEntry :: navbarEntry('img-to-pdf', 'picture_as_pdf', 'home.imageToPdf.title', 'home.imageToPdf.desc', 'imageToPdf.tags', 'convertto')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/navbarEntry :: navbarEntry('file-to-pdf', 'draft', 'home.fileToPDF.title', 'home.fileToPDF.desc', 'fileToPDF.tags', 'convertto')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/navbarEntry :: navbarEntry('url-to-pdf', 'link', 'home.URLToPDF.title', 'home.URLToPDF.desc', 'URLToPDF.tags', 'convertto')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/navbarEntry :: navbarEntry('html-to-pdf', 'html', 'home.HTMLToPDF.title', 'home.HTMLToPDF.desc', 'HTMLToPDF.tags', 'convertto')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/navbarEntry :: navbarEntry('markdown-to-pdf', 'markdown', 'home.MarkdownToPDF.title', 'home.MarkdownToPDF.desc', 'MarkdownToPDF.tags', 'convertto')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/navbarEntry :: navbarEntry('book-to-pdf', 'book', 'home.BookToPDF.title', 'home.BookToPDF.desc', 'BookToPDF.tags', 'convertto')}">
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/featureGroupHeader :: featureGroupHeader(groupTitle=#{navbar.sections.convertFrom})}">
|
||||
</div>
|
||||
<div class="nav-group-container">
|
||||
<div
|
||||
th:replace="~{fragments/navbarEntry :: navbarEntry('pdf-to-img', 'photo_library', 'home.pdfToImage.title', 'home.pdfToImage.desc', 'pdfToImage.tags', 'convert')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/navbarEntry :: navbarEntry('pdf-to-pdfa', 'picture_as_pdf', 'home.pdfToPDFA.title', 'home.pdfToPDFA.desc', 'pdfToPDFA.tags', 'convert')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/navbarEntry :: navbarEntry('pdf-to-word', 'description', 'home.PDFToWord.title', 'home.PDFToWord.desc', 'PDFToWord.tags', 'convert')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/navbarEntry :: navbarEntry('pdf-to-presentation', 'slideshow', 'home.PDFToPresentation.title', 'home.PDFToPresentation.desc', 'PDFToPresentation.tags', 'convert')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/navbarEntry :: navbarEntry('pdf-to-text', 'text_fields', 'home.PDFToText.title', 'home.PDFToText.desc', 'PDFToText.tags', 'convert')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/navbarEntry :: navbarEntry('pdf-to-html', 'html', 'home.PDFToHTML.title', 'home.PDFToHTML.desc', 'PDFToHTML.tags', 'convert')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/navbarEntry :: navbarEntry('pdf-to-xml', 'code', 'home.PDFToXML.title', 'home.PDFToXML.desc', 'PDFToXML.tags', 'convert')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/navbarEntry :: navbarEntry('pdf-to-csv', 'csv', 'home.tableExtraxt.title', 'home.tableExtraxt.desc', 'tableExtraxt.tags', 'convert')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/navbarEntry :: navbarEntry('pdf-to-book', 'book', 'home.PDFToBook.title', 'home.PDFToBook.desc', 'PDFToBook.tags', 'convert')}">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="groupSecurity" class="feature-group">
|
||||
<div
|
||||
th:replace="~{fragments/featureGroupHeader :: featureGroupHeader(groupTitle=#{navbar.sections.security})}">
|
||||
</div>
|
||||
<div class="nav-group-container">
|
||||
<div
|
||||
th:replace="~{fragments/navbarEntry :: navbarEntry('add-password', 'lock', 'home.addPassword.title', 'home.addPassword.desc', 'addPassword.tags', 'security')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/navbarEntry :: navbarEntry('remove-password', 'lock_open_right', 'home.removePassword.title', 'home.removePassword.desc', 'removePassword.tags', 'security')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/navbarEntry :: navbarEntry('change-permissions', 'encrypted', 'home.permissions.title', 'home.permissions.desc', 'permissions.tags', 'security')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/navbarEntry :: navbarEntry('sign', 'signature', 'home.sign.title', 'home.sign.desc', 'sign.tags', 'security')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/navbarEntry :: navbarEntry('cert-sign', 'workspace_premium', 'home.certSign.title', 'home.certSign.desc', 'certSign.tags', 'security')}">
|
||||
</div>
|
||||
|
||||
<div
|
||||
th:replace="~{fragments/navbarEntry :: navbarEntry('validate-signature', 'verified', 'home.validateSignature.title', 'home.validateSignature.desc', 'validateSignature.tags', 'security')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/navbarEntry :: navbarEntry('remove-cert-sign', 'remove_moderator', 'home.removeCertSign.title', 'home.removeCertSign.desc', 'removeCertSign.tags', 'security')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/navbarEntry :: navbarEntry('sanitize-pdf', 'sanitizer', 'home.sanitizePdf.title', 'home.sanitizePdf.desc', 'sanitizePdf.tags', 'security')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/navbarEntryCustom :: navbarEntry('auto-redact', '/images/redact-auto.svg#icon-redact-auto', 'home.autoRedact.title', 'home.autoRedact.desc', 'autoRedact.tags', 'security')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/navbarEntryCustom :: navbarEntry('redact', '/images/redact-manual.svg#icon-redact-manual', 'home.redact.title', 'home.redact.desc', 'redact.tags', 'security')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/navbarEntry :: navbarEntry('stamp', 'approval', 'home.AddStampRequest.title', 'home.AddStampRequest.desc', 'AddStampRequest.tags', 'security')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/navbarEntry :: navbarEntry('add-watermark', 'water_drop', 'home.watermark.title', 'home.watermark.desc', 'watermark.tags', 'security')}">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="groupView" class="feature-group">
|
||||
<div th:replace="~{fragments/featureGroupHeader :: featureGroupHeader(groupTitle=#{navbar.sections.edit})}">
|
||||
</div>
|
||||
<div class="nav-group-container">
|
||||
<div
|
||||
th:replace="~{fragments/navbarEntry :: navbarEntry('view-pdf', 'menu_book', 'home.viewPdf.title', 'home.viewPdf.desc', 'viewPdf.tags', 'other')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/navbarEntry :: navbarEntry('add-page-numbers', '123', 'home.add-page-numbers.title', 'home.add-page-numbers.desc', 'add-page-numbers.tags', 'other')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/navbarEntry :: navbarEntry('add-image', 'text_fields', 'home.addImage.title', 'home.addImage.desc', 'addImage.tags', 'other')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/navbarEntry :: navbarEntry('change-metadata', 'assignment', 'home.changeMetadata.title', 'home.changeMetadata.desc', 'changeMetadata.tags', 'other')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/navbarEntry :: navbarEntry('ocr-pdf', 'quick_reference_all', 'home.ocr.title', 'home.ocr.desc', 'ocr.tags', 'other')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/navbarEntry :: navbarEntry('extract-images', 'photo_library', 'home.extractImages.title', 'home.extractImages.desc', 'extractImages.tags', 'other')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/navbarEntry :: navbarEntry('flatten', 'layers_clear', 'home.flatten.title', 'home.flatten.desc', 'flatten.tags', 'other')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/navbarEntry :: navbarEntry('remove-blanks', 'scan_delete', 'home.removeBlanks.title', 'home.removeBlanks.desc', 'removeBlanks.tags', 'other')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/navbarEntry :: navbarEntry('remove-annotations', 'thread_unread', 'home.removeAnnotations.title', 'home.removeAnnotations.desc', 'removeAnnotations.tags', 'other')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/navbarEntry :: navbarEntry('compare', 'compare', 'home.compare.title', 'home.compare.desc', 'compare.tags', 'other')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/navbarEntry :: navbarEntry('get-info-on-pdf', 'info', 'home.getPdfInfo.title', 'home.getPdfInfo.desc', 'getPdfInfo.tags', 'other')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/navbarEntry :: navbarEntry('remove-image-pdf', 'remove_selection', 'home.removeImagePdf.title', 'home.removeImagePdf.desc', 'removeImagePdf.tags', 'other')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/navbarEntry :: navbarEntry('replace-color-pdf', 'format_color_fill', 'home.replaceColorPdf.title', 'home.replaceColorPdf.desc', 'replaceColorPdf.tags', 'other')}">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="groupAdvanced" class="feature-group">
|
||||
<div
|
||||
th:replace="~{fragments/featureGroupHeader :: featureGroupHeader(groupTitle=#{navbar.sections.advance})}">
|
||||
</div>
|
||||
<div class="nav-group-container">
|
||||
<div
|
||||
th:replace="~{fragments/navbarEntry :: navbarEntry('pipeline', 'family_history', 'home.pipeline.title', 'home.pipeline.desc', 'pipeline.tags', 'advance')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/navbarEntry :: navbarEntry('adjust-contrast', 'palette', 'home.adjust-contrast.title', 'home.adjust-contrast.desc', 'adjust-contrast.tags', 'advance')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/navbarEntry :: navbarEntry('compress-pdf', 'zoom_in_map', 'home.compressPdfs.title', 'home.compressPdfs.desc', 'compressPdfs.tags', 'advance')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/navbarEntry :: navbarEntry('extract-image-scans', 'scanner', 'home.ScannerImageSplit.title', 'home.ScannerImageSplit.desc', 'ScannerImageSplit.tags', 'advance')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/navbarEntry :: navbarEntry('repair', 'build', 'home.repair.title', 'home.repair.desc', 'repair.tags', 'advance')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/navbarEntryCustom :: navbarEntry('auto-rename', '/images/rename.svg#icon-rename', 'home.auto-rename.title', 'home.auto-rename.desc', 'auto-rename.tags', 'advance')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/navbarEntryCustom :: navbarEntry('auto-split-pdf', '/images/split-auto.svg#icon-split-auto', 'home.autoSplitPDF.title', 'home.autoSplitPDF.desc', 'autoSplitPDF.tags', 'advance')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/navbarEntry :: navbarEntry('show-javascript', 'javascript', 'home.showJS.title', 'home.showJS.desc', 'showJS.tags', 'advance')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/navbarEntryCustom :: navbarEntry('split-by-size-or-count', '/images/split-size.svg#icon-split-size', 'home.autoSizeSplitPDF.title', 'home.autoSizeSplitPDF.desc', 'autoSizeSplitPDF.tags', 'advance')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/navbarEntry :: navbarEntry('overlay-pdf', 'layers', 'home.overlay-pdfs.title', 'home.overlay-pdfs.desc', 'overlay-pdfs.tags', 'advance')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/navbarEntry :: navbarEntry('split-pdf-by-sections', 'grid_on', 'home.split-by-sections.title', 'home.split-by-sections.desc', 'split-by-sections.tags', 'advance')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/navbarEntryCustom :: navbarEntry('split-pdf-by-chapters', '/images/split-chapters.svg#icon-split-chapters', 'home.splitPdfByChapters.title', 'home.splitPdfByChapters.desc', 'splitPdfByChapters.tags', 'advance')}">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</th:block>
|
@ -1,11 +1,13 @@
|
||||
<div th:fragment="navbar" class="mx-auto">
|
||||
<div th:fragment="navbar" class="mx-auto" style="position: sticky; top:0; z-index:10000">
|
||||
<script th:src="@{'/js/languageSelection.js'}"></script>
|
||||
<script th:src="@{'/js/navbar.js'}"></script>
|
||||
<script th:src="@{'/js/additionalLanguageCode.js'}"></script>
|
||||
<script th:inline="javascript">
|
||||
// Initializing the scripts
|
||||
initLanguageSettings();
|
||||
toolsManager();
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
toolsManager();
|
||||
});
|
||||
</script>
|
||||
<script th:inline="javascript">
|
||||
const currentVersion = /*[[${@appVersion}]]*/ '';
|
||||
@ -16,7 +18,11 @@
|
||||
<script th:src="@{'/js/homecard.js'}"></script>
|
||||
<script th:src="@{'/js/githubVersion.js'}"></script>
|
||||
<form th:action="@{'/dummyFormToPopulateCSRF'}" method="post" enctype="multipart/form-data"></form>
|
||||
<nav class="navbar navbar-expand-xl">
|
||||
<nav class="navbar navbar-expand-xl" style="
|
||||
background: var(--md-nav-background);
|
||||
border-bottom-style: solid;
|
||||
border-bottom-width: 1px;
|
||||
border-color: var(--md-nav-color-on-seperator)">
|
||||
<div class="container ">
|
||||
<a class="navbar-brand" th:href="@{'/'}" style="display: flex;">
|
||||
<img class="main-icon" th:src="@{'/favicon.svg'}" alt="icon">
|
||||
@ -32,7 +38,7 @@
|
||||
<ul class="navbar-nav me-auto flex-nowrap">
|
||||
|
||||
<!-- All Tools -->
|
||||
<li class="nav-item dropdown dropdown-mega position-static">
|
||||
<li id="navItemToHide" class="nav-item dropdown dropdown-mega position-static">
|
||||
<a class="nav-link" id="navbarDropdown-1" href="#" role="button" data-bs-toggle="dropdown"
|
||||
aria-haspopup="true" aria-expanded="false">
|
||||
<span class="material-symbols-rounded">
|
||||
@ -41,231 +47,10 @@
|
||||
<span class="icon-text" th:data-text="#{navbar.allTools}" th:text="#{navbar.allTools}"></span>
|
||||
</a>
|
||||
<div class="dropdown-menu dropdown-menu-tp" aria-labelledby="navbarDropdown-1">
|
||||
<div class="dropdown-menu-wrapper">
|
||||
<div class='mega-content px-md-4'>
|
||||
<div class="container-fluid">
|
||||
<div class="row">
|
||||
<!-- Page tools menu items -->
|
||||
<div class="navbar-item col-lg-2 col-sm-6 py px-xl-1">
|
||||
<h6 class="menu-title" th:text="#{navbar.sections.organize}"></h6>
|
||||
<div
|
||||
th:replace="~{fragments/navbarEntry :: navbarEntry ('multi-tool', 'construction', 'home.multiTool.title', 'home.multiTool.desc', 'multiTool.tags', 'organize')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/navbarEntry :: navbarEntry ('merge-pdfs', 'add_to_photos', 'home.merge.title', 'home.merge.desc', 'merge.tags', 'organize')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/navbarEntry :: navbarEntry ('split-pdfs', 'cut', 'home.split.title', 'home.split.desc', 'split.tags', 'organize')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/navbarEntry :: navbarEntry ('rotate-pdf', 'rotate_right', 'home.rotate.title', 'home.rotate.desc', 'rotate.tags', 'organize')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/navbarEntry :: navbarEntry ('remove-pages', 'delete', 'home.removePages.title', 'home.removePages.desc', 'removePages.tags', 'organize')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/navbarEntry :: navbarEntry ('pdf-organizer', 'format_list_bulleted', 'home.pdfOrganiser.title', 'home.pdfOrganiser.desc', 'pdfOrganiser.tags', 'organize')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/navbarEntry :: navbarEntry ('multi-page-layout', 'dashboard', 'home.pageLayout.title', 'home.pageLayout.desc', 'pageLayout.tags', 'organize')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/navbarEntry :: navbarEntry ('scale-pages', 'fullscreen', 'home.scalePages.title', 'home.scalePages.desc', 'scalePages.tags', 'organize')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/navbarEntry :: navbarEntry ('crop', 'crop', 'home.crop.title', 'home.crop.desc', 'crop.tags', 'organize')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/navbarEntry :: navbarEntry ('extract-page', 'upload', 'home.extractPage.title', 'home.extractPage.desc', 'extractPage.tags', 'organize')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/navbarEntry :: navbarEntry ('pdf-to-single-page', 'looks_one', 'home.PdfToSinglePage.title', 'home.PdfToSinglePage.desc', 'PdfToSinglePage.tags', 'organize')}">
|
||||
</div>
|
||||
</div>
|
||||
<div id="stacked" class="navbar-item col-lg-2 col-sm-6 py px-xl-1 px-2"
|
||||
style="display:flex; flex-direction: column;">
|
||||
<!-- Convert to PDF menu items -->
|
||||
<div class="navbar-item py px-xl-1 px-2" style="margin-bottom: 1rem;">
|
||||
<h6 class="menu-title" th:text="#{navbar.sections.convertTo}"></h6>
|
||||
<div
|
||||
th:replace="~{fragments/navbarEntry :: navbarEntry ('img-to-pdf', 'picture_as_pdf', 'home.imageToPdf.title', 'home.imageToPdf.desc', 'imageToPdf.tags', 'image')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/navbarEntry :: navbarEntry ('file-to-pdf', 'draft', 'home.fileToPDF.title', 'home.fileToPDF.desc', 'fileToPDF.tags', 'convert')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/navbarEntry :: navbarEntry ('url-to-pdf', 'link', 'home.URLToPDF.title', 'home.URLToPDF.desc', 'URLToPDF.tags', 'convert')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/navbarEntry :: navbarEntry ('html-to-pdf', 'html', 'home.HTMLToPDF.title', 'home.HTMLToPDF.desc', 'HTMLToPDF.tags', 'convert')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/navbarEntry :: navbarEntry ('markdown-to-pdf', 'markdown', 'home.MarkdownToPDF.title', 'home.MarkdownToPDF.desc', 'MarkdownToPDF.tags', 'convert')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/navbarEntry :: navbarEntry ('book-to-pdf', 'book', 'home.BookToPDF.title', 'home.BookToPDF.desc', 'BookToPDF.tags', 'convert')}">
|
||||
</div>
|
||||
</div>
|
||||
<!-- Convert from PDF menu items -->
|
||||
<div class="navbar-item py px-xl-1">
|
||||
<h6 class="menu-title" th:text="#{navbar.sections.convertFrom}"></h6>
|
||||
<div
|
||||
th:replace="~{fragments/navbarEntry :: navbarEntry ('pdf-to-img', 'photo_library', 'home.pdfToImage.title', 'home.pdfToImage.desc', 'pdfToImage.tags', 'image')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/navbarEntry :: navbarEntry ('pdf-to-word', 'description', 'home.PDFToWord.title', 'home.PDFToWord.desc', 'PDFToWord.tags', 'word')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/navbarEntry :: navbarEntry ('pdf-to-presentation', 'slideshow', 'home.PDFToPresentation.title', 'home.PDFToPresentation.desc', 'PDFToPresentation.tags', 'ppt')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/navbarEntry :: navbarEntry ('pdf-to-text', 'text_fields', 'home.PDFToText.title', 'home.PDFToText.desc', 'PDFToText.tags', 'convert')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/navbarEntry :: navbarEntry ('pdf-to-html', 'html', 'home.PDFToHTML.title', 'home.PDFToHTML.desc', 'PDFToHTML.tags', 'convert')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/navbarEntry :: navbarEntry ('pdf-to-xml', 'code', 'home.PDFToXML.title', 'home.PDFToXML.desc', 'PDFToXML.tags', 'convert')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/navbarEntry :: navbarEntry ('pdf-to-pdfa', 'picture_as_pdf', 'home.pdfToPDFA.title', 'home.pdfToPDFA.desc', 'pdfToPDFA.tags', 'convert')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/navbarEntry :: navbarEntry ('pdf-to-csv', 'csv', 'home.tableExtraxt.title', 'home.tableExtraxt.desc', 'pdfToPDFA.tags', 'convert')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/navbarEntry :: navbarEntry ('pdf-to-book', 'book', 'home.PDFToBook.title', 'home.PDFToBook.desc', 'PDFToBook.tags', 'convert')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/navbarEntry :: navbarEntry ('pdf-to-markdown', 'markdown_copy', 'home.PDFToMarkdown.title', 'home.PDFToMarkdown.desc', 'PDFToMarkdown.tags', 'convert')}">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Security menu items -->
|
||||
<div class="navbar-item col-lg-2 col-sm-6 py px-xl-1 px-2">
|
||||
<h6 class="menu-title" th:text="#{navbar.sections.security}"></h6>
|
||||
<div
|
||||
th:replace="~{fragments/navbarEntry :: navbarEntry ('sign', 'signature', 'home.sign.title', 'home.sign.desc', 'sign.tags', 'sign')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/navbarEntry :: navbarEntry ('add-password', 'lock', 'home.addPassword.title', 'home.addPassword.desc', 'addPassword.tags', 'security')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/navbarEntry :: navbarEntry ('remove-password', 'lock_open_right', 'home.removePassword.title', 'home.removePassword.desc', 'removePassword.tags', 'security')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/navbarEntry :: navbarEntry ('change-permissions', 'encrypted', 'home.permissions.title', 'home.permissions.desc', 'permissions.tags', 'security')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/navbarEntry :: navbarEntry ('add-watermark', 'water_drop', 'home.watermark.title', 'home.watermark.desc', 'watermark.tags', 'security')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/navbarEntry :: navbarEntry ('cert-sign', 'workspace_premium', 'home.certSign.title', 'home.certSign.desc', 'certSign.tags', 'security')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/navbarEntry :: navbarEntry('validate-signature','verified','home.validateSignature.title','home.validateSignature.desc','validateSignature.tags','security')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/navbarEntry :: navbarEntry ('remove-cert-sign', 'remove_moderator', 'home.removeCertSign.title', 'home.removeCertSign.desc', 'removeCertSign.tags', 'security')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/navbarEntry :: navbarEntry ('sanitize-pdf', 'sanitizer', 'home.sanitizePdf.title', 'home.sanitizePdf.desc', 'sanitizePdf.tags', 'security')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/navbarEntry :: navbarEntry ('auto-redact', 'contract_delete', 'home.autoRedact.title', 'home.autoRedact.desc', 'autoRedact.tags', 'security')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/navbarEntry :: navbarEntry ('redact', 'playlist_remove', 'home.redact.title', 'home.redact.desc', 'redact.tags', 'security')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/navbarEntry :: navbarEntry ('stamp', 'approval', 'home.AddStampRequest.title', 'home.AddStampRequest.desc', 'AddStampRequest.tags', 'security')}">
|
||||
</div>
|
||||
</div>
|
||||
<!-- View & Edit menu items -->
|
||||
<div class="navbar-item col-lg-2 col-sm-6 py px-xl-1 px-2">
|
||||
<h6 class="menu-title" th:text="#{navbar.sections.edit}"></h6>
|
||||
<div
|
||||
th:replace="~{fragments/navbarEntry :: navbarEntry ('view-pdf', 'menu_book', 'home.viewPdf.title', 'home.viewPdf.desc', 'viewPdf.tags', 'other')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/navbarEntry :: navbarEntry ('ocr-pdf', 'quick_reference_all', 'home.ocr.title', 'home.ocr.desc', 'ocr.tags', 'other')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/navbarEntry :: navbarEntry ('add-page-numbers', '123', 'home.add-page-numbers.title', 'home.add-page-numbers.desc', 'add-page-numbers.tags', 'other')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/navbarEntry :: navbarEntry ('add-image', 'add_photo_alternate', 'home.addImage.title', 'home.addImage.desc', 'addImage.tags', 'other')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/navbarEntry :: navbarEntry ('extract-images', 'wallpaper', 'home.extractImages.title', 'home.extractImages.desc', 'extractImages.tags', 'other')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/navbarEntry :: navbarEntry ('flatten', 'layers_clear', 'home.flatten.title', 'home.flatten.desc', 'flatten.tags', 'other')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/navbarEntry :: navbarEntry ('remove-annotations', 'thread_unread', 'home.removeAnnotations.title', 'home.removeAnnotations.desc', 'removeAnnotations.tags', 'other')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/navbarEntry :: navbarEntry ('remove-blanks', 'scan_delete', 'home.removeBlanks.title', 'home.removeBlanks.desc', 'removeBlanks.tags', 'other')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/navbarEntry :: navbarEntry ('compare', 'compare', 'home.compare.title', 'home.compare.desc', 'compare.tags', 'other')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/navbarEntry :: navbarEntry ('change-metadata', 'assignment', 'home.changeMetadata.title', 'home.changeMetadata.desc', 'changeMetadata.tags', 'other')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/navbarEntry :: navbarEntry ('get-info-on-pdf', 'info', 'home.getPdfInfo.title', 'home.getPdfInfo.desc', 'getPdfInfo.tags', 'other')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/navbarEntry :: navbarEntry ('remove-image-pdf','remove_selection', 'home.removeImagePdf.title', 'home.removeImagePdf.desc', 'removeImagePdf.tags', 'other')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/navbarEntry :: navbarEntry ('replace-and-invert-color-pdf','format_color_fill', 'replace-color.title', 'home.replaceColorPdf.desc', 'replaceColorPdf.tags', 'other')}">
|
||||
</div>
|
||||
</div>
|
||||
<!-- Advance menu items -->
|
||||
<div class="navbar-item col-lg-2 col-sm-6 py px-xl-1 px-2">
|
||||
<h6 class="menu-title" th:text="#{navbar.sections.advance}"></h6>
|
||||
<div
|
||||
th:replace="~{fragments/navbarEntry :: navbarEntry ('compress-pdf', 'zoom_in_map', 'home.compressPdfs.title', 'home.compressPdfs.desc', 'compressPdfs.tags', 'advance')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/navbarEntry :: navbarEntry ('pipeline', 'family_history', 'home.pipeline.title', 'home.pipeline.desc', 'pipeline.tags', 'advance')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/navbarEntryCustom :: navbarEntry ('auto-rename', '/images/rename.svg#icon-rename', 'home.auto-rename.title', 'home.auto-rename.desc', 'auto-rename.tags', 'advance')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/navbarEntry :: navbarEntry ('repair', 'build', 'home.repair.title', 'home.repair.desc', 'repair.tags', 'advance')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/navbarEntry :: navbarEntry ('adjust-contrast', 'palette', 'home.adjust-contrast.title', 'home.adjust-contrast.desc', 'adjust-contrast.tags', 'advance')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/navbarEntry :: navbarEntry ('overlay-pdf', 'layers', 'home.overlay-pdfs.title', 'home.overlay-pdfs.desc', 'overlay-pdfs.tags', 'advance')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/navbarEntry :: navbarEntry ('auto-split-pdf', 'cut', 'home.autoSplitPDF.title', 'home.autoSplitPDF.desc', 'autoSplitPDF.tags', 'advance')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/navbarEntry :: navbarEntry ('split-pdf-by-sections', 'grid_on', 'home.split-by-sections.title', 'home.split-by-sections.desc', 'split-by-sections.tags', 'advance')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/navbarEntry :: navbarEntry ('split-pdf-by-chapters', 'book', 'home.splitPdfByChapters.title', 'home.splitPdfByChapters.desc', 'splitPdfByChapters.tags', 'advance')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/navbarEntry :: navbarEntry ('split-by-size-or-count', 'vertical_split', 'home.autoSizeSplitPDF.title', 'home.autoSizeSplitPDF.desc', 'autoSizeSplitPDF.tags', 'advance')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/navbarEntry :: navbarEntry ('extract-image-scans', 'scanner', 'home.ScannerImageSplit.title', 'home.ScannerImageSplit.desc', 'ScannerImageSplit.tags', 'advance')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/navbarEntry :: navbarEntry ('show-javascript', 'javascript', 'home.showJS.title', 'home.showJS.desc', 'showJS.tags', 'advance')}">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="dropdown-menu-wrapper" style="justify-content: center; display:flex">
|
||||
<div class="feature-rows">
|
||||
|
||||
<th:block th:insert="~{fragments/navElements.html :: navElements}"></th:block>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -480,4 +265,18 @@
|
||||
</div>
|
||||
</div>
|
||||
<script th:src="@{'/js/settings.js'}"></script>
|
||||
<script>
|
||||
window.onload = function () {
|
||||
updateFavoritesDropdown();
|
||||
|
||||
}
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
const navbarLink = document.querySelector(".navbar-brand");
|
||||
if (localStorage.getItem("defaultView") === "home-legacy") {
|
||||
navbarLink.setAttribute("href", "/home-legacy");
|
||||
} else {
|
||||
navbarLink.setAttribute("href", "/");
|
||||
}
|
||||
});
|
||||
</script>
|
||||
</div>
|
@ -1,11 +1,18 @@
|
||||
<th:block th:fragment="navbarEntry(endpoint, toolIcon, titleKey, descKey, tagKey, toolGroup)"
|
||||
th:if="${@endpointConfiguration.isEndpointEnabled(endpoint)}">
|
||||
<a class="dropdown-item" href="#" th:href="@{${endpoint}}"
|
||||
th:classappend="${endpoint.equals(currentPage)} ? ${toolGroup} + ' active' : '' + ${toolGroup}" th:title="#{${descKey}}"
|
||||
th:data-bs-tags="#{${tagKey}}">
|
||||
<div class="icon" alt="icon" th:class="@{${toolGroup}}">
|
||||
<span class="material-symbols-rounded nav-icon" th:text="@{${toolIcon}}"></span>
|
||||
th:if="${@endpointConfiguration.isEndpointEnabled(endpoint)}">
|
||||
<a th:id="@{${endpoint}}" class="dropdown-item" style="position:relative" th:href="@{${endpoint}}"
|
||||
th:data-bs-link="@{${endpoint}}"
|
||||
th:classappend="${endpoint.equals(currentPage)} ? ${toolGroup} + ' active' : '' + ${toolGroup}"
|
||||
th:data-bs-tags="#{${tagKey}}" th:data-bs-title='#{${titleKey}}'>
|
||||
<div style="height:2.7rem; align-items: center;display: flex;" th:title="#{${descKey}}" class="icon" alt="icon"
|
||||
th:class="@{${toolGroup}}">
|
||||
<span class="material-symbols-rounded nav-icon" th:text="@{${toolIcon}}" style=" align-items:center; display: flex; justify-content: center; height:2.7rem; width:2.7rem"></span>
|
||||
<span class="icon-text" th:text="#{${titleKey}}"></span>
|
||||
</div>
|
||||
<span class="material-symbols-rounded favorite-icon" style="display: none;" th:data-endpoint="@{${endpoint}}"
|
||||
th:onclick="'addToFavorites(\'' + @{${endpoint}} + '\')'">
|
||||
add
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</th:block>
|
@ -1,13 +1,20 @@
|
||||
<th:block th:fragment="navbarEntry(endpoint, toolIcon, titleKey, descKey, tagKey, toolGroup)"
|
||||
th:if="${@endpointConfiguration.isEndpointEnabled(endpoint)}">
|
||||
<a class="dropdown-item" href="#" th:href="@{${endpoint}}"
|
||||
th:if="${@endpointConfiguration.isEndpointEnabled(endpoint)}">
|
||||
<a th:id="@{${endpoint}}" class="dropdown-item" style="position:relative" th:href="@{${endpoint}}"
|
||||
th:data-bs-link="@{${endpoint}}"
|
||||
th:classappend="${endpoint.equals(currentPage)} ? ${toolGroup} + ' active' : '' + ${toolGroup}"
|
||||
th:title="#{${descKey}}" th:data-bs-tags="#{${tagKey}}">
|
||||
<div class="icon" alt="icon" th:class="@{${toolGroup}}">
|
||||
<svg class="nav-icon" style="height: 2.5rem; width:2.5rem">
|
||||
<use th:xlink:href="@{${toolIcon}}"></use>
|
||||
th:data-bs-tags="#{${tagKey}}" th:data-bs-title='#{${titleKey}}'>
|
||||
<div style="height:2.5rem;align-items: center;display: flex" th:title="#{${descKey}}" class="icon" alt="icon"
|
||||
th:class="@{${toolGroup}}">
|
||||
<svg class="nav-icon" style="height: 2.7rem; width:2.7rem; align-items:center; display: flex; justify-content: center;">
|
||||
<use th:href="@{${toolIcon}}"></use>
|
||||
</svg>
|
||||
<span class="icon-text" th:text="#{${titleKey}}"></span>
|
||||
</div>
|
||||
<span class="material-symbols-rounded favorite-icon" style="display: none;" th:data-endpoint="@{${endpoint}}"
|
||||
th:onclick="'addToFavorites(\'' + @{${endpoint}} + '\')'">
|
||||
star
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</th:block>
|
522
src/main/resources/templates/home-legacy.html
Normal file
522
src/main/resources/templates/home-legacy.html
Normal file
@ -0,0 +1,522 @@
|
||||
<!DOCTYPE html>
|
||||
<html th:lang="${#locale.language}" th:dir="#{language.direction}" th:data-language="${#locale.toString()}"
|
||||
xmlns:th="https://www.thymeleaf.org">
|
||||
|
||||
<head>
|
||||
<th:block th:insert="~{fragments/common :: head(title='')}"></th:block>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="page-container">
|
||||
<div id="content-wrap">
|
||||
<th:block th:insert="~{fragments/navbar.html :: navbar}"></th:block>
|
||||
<!-- Jumbotron -->
|
||||
<div class="p-5 rounded d-none d-md-block" id="jumbotron">
|
||||
<div class="container">
|
||||
<h1 class="display-4 fw-normal" th:text="${@appName}"></h1>
|
||||
<p class="lead fs-4"
|
||||
th:text="${@homeText != 'null' and @homeText != null and @homeText != ''} ? ${@homeText} : #{home.desc}">
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<br class="d-md-none">
|
||||
<!-- Features -->
|
||||
<script th:src="@{'/js/homecard-legacy.js'}"></script>
|
||||
<div class=" container">
|
||||
<br>
|
||||
<span class="material-symbols-rounded search-icon">
|
||||
search
|
||||
</span>
|
||||
<input type="text" id="searchBar" onkeyup="filterCards()" th:placeholder="#{home.searchBar}" autofocus>
|
||||
<div style="display: flex; align-items: center;">
|
||||
<a href="home" onclick="setAsDefault('home')" style="text-decoration: none; color: inherit; cursor: pointer; display: flex; align-items: center;">
|
||||
<span th:text="#{home.newHomePage}">
|
||||
</span>
|
||||
<span class="material-symbols-rounded toggle-favourites" style="font-size: 2rem; margin-left: 0.2rem;" >
|
||||
home
|
||||
</span>
|
||||
</a>
|
||||
</div>
|
||||
<div id="filtersContainer">
|
||||
<span class="material-symbols-rounded filter-button" onclick="toggleFavoritesOnly()">
|
||||
star
|
||||
</span>
|
||||
<span class="material-symbols-rounded filter-button" onclick="expandCollapseAll(true)">
|
||||
expand_all
|
||||
</span>
|
||||
<span class="material-symbols-rounded filter-button" onclick="expandCollapseAll(false)">
|
||||
collapse_all
|
||||
</span>
|
||||
<span class="material-symbols-rounded filter-button hidden" onclick="switchViewMode()">
|
||||
dashboard
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="features-container">
|
||||
|
||||
<div th:if="${@shouldShow}" class="feature-card favorite update-notice" id="update-link"
|
||||
style="display: none;">
|
||||
<a href="https://github.com/Stirling-Tools/Stirling-PDF/releases" target="_blank" rel="noopener">
|
||||
<div class="d-flex align-items-center">
|
||||
<div id="tool-icon" class="advance" alt="icon">
|
||||
<span class="material-symbols-rounded nav-icon">update</span>
|
||||
</div>
|
||||
<div id="tool-text">
|
||||
<h5 class="card-title" th:text="#{settings.update}"></h5>
|
||||
<p class="card-text" id="app-update"></p>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div id="groupFavorites" class="feature-group-legacy">
|
||||
<div th:replace="~{fragments/featureGroupHeaderLegacy :: featureGroupHeader(groupTitle=#{navbar.favorite})}">
|
||||
</div>
|
||||
<div class="feature-group-container">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div id="popularTools" class="feature-group-legacy">
|
||||
<div
|
||||
th:replace="~{fragments/featureGroupHeaderLegacy :: featureGroupHeader(groupTitle=#{navbar.sections.popular})}">
|
||||
</div>
|
||||
<div class="feature-group-container">
|
||||
<div
|
||||
th:replace="~{fragments/card :: card(id='view-pdf', cardTitle=#{home.viewPdf.title}, cardText=#{home.viewPdf.desc}, cardLink='view-pdf', toolIcon='menu_book', tags=#{viewPdf.tags}, toolGroup='other')}">
|
||||
</div>
|
||||
|
||||
<div
|
||||
th:replace="~{fragments/card :: card(id='multi-tool', cardTitle=#{home.multiTool.title}, cardText=#{home.multiTool.desc}, cardLink='multi-tool', toolIcon='construction', tags=#{multiTool.tags}, toolGroup='organize')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/card :: card(id='pipeline', cardTitle=#{home.pipeline.title}, cardText=#{home.pipeline.desc}, cardLink='pipeline', toolIcon='family_history', tags=#{pipeline.tags}, toolGroup='advance')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/card :: card(id='compress-pdf', cardTitle=#{home.compressPdfs.title}, cardText=#{home.compressPdfs.desc}, cardLink='compress-pdf', toolIcon='zoom_in_map', tags=#{compressPdfs.tags}, toolGroup='advance')}">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
<div id="groupOrganize" class="feature-group-legacy">
|
||||
<div
|
||||
th:replace="~{fragments/featureGroupHeaderLegacy :: featureGroupHeader(groupTitle=#{navbar.sections.organize})}">
|
||||
</div>
|
||||
<div class="feature-group-container">
|
||||
<div
|
||||
th:replace="~{fragments/card :: card(id='multi-tool', cardTitle=#{home.multiTool.title}, cardText=#{home.multiTool.desc}, cardLink='multi-tool', toolIcon='construction', tags=#{multiTool.tags}, toolGroup='organize')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/card :: card(id='merge-pdfs', cardTitle=#{home.merge.title}, cardText=#{home.merge.desc}, cardLink='merge-pdfs', toolIcon='add_to_photos', tags=#{merge.tags}, toolGroup='organize')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/card :: card(id='split-pdfs', cardTitle=#{home.split.title}, cardText=#{home.split.desc}, cardLink='split-pdfs', toolIcon='cut', tags=#{split.tags}, toolGroup='organize')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/card :: card(id='rotate-pdf', cardTitle=#{home.rotate.title}, cardText=#{home.rotate.desc}, cardLink='rotate-pdf', toolIcon='rotate_right', tags=#{rotate.tags}, toolGroup='organize')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/card :: card(id='crop', cardTitle=#{home.crop.title}, cardText=#{home.crop.desc}, cardLink='crop', toolIcon='crop', tags=#{crop.tags}, toolGroup='organize')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/card :: card(id='pdf-organizer', cardTitle=#{home.pdfOrganiser.title}, cardText=#{home.pdfOrganiser.desc}, cardLink='pdf-organizer', toolIcon='format_list_bulleted', tags=#{pdfOrganiser.tags}, toolGroup='organize')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/card :: card(id='remove-pages', cardTitle=#{home.removePages.title}, cardText=#{home.removePages.desc}, cardLink='remove-pages', toolIcon='delete', tags=#{removePages.tags}, toolGroup='organize')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/card :: card(id='multi-page-layout', cardTitle=#{home.pageLayout.title}, cardText=#{home.pageLayout.desc}, cardLink='multi-page-layout', toolIcon='dashboard', tags=#{pageLayout.tags}, toolGroup='organize')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/card :: card(id='scale-pages', cardTitle=#{home.scalePages.title}, cardText=#{home.scalePages.desc}, cardLink='scale-pages', toolIcon='fullscreen', tags=#{scalePages.tags}, toolGroup='organize')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/card :: card(id='extract-page', cardTitle=#{home.extractPage.title}, cardText=#{home.extractPage.desc}, cardLink='extract-page', toolIcon='upload', tags=#{extractPage.tags}, toolGroup='organize')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/card :: card(id='pdf-to-single-page', cardTitle=#{home.PdfToSinglePage.title}, cardText=#{home.PdfToSinglePage.desc}, cardLink='pdf-to-single-page', toolIcon='looks_one', tags=#{PdfToSinglePage.tags}, toolGroup='organize')}">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="groupConvertTo" class="feature-group-legacy">
|
||||
<div
|
||||
th:replace="~{fragments/featureGroupHeaderLegacy :: featureGroupHeader(groupTitle=#{navbar.sections.convertTo})}">
|
||||
</div>
|
||||
<div class="feature-group-container">
|
||||
<div
|
||||
th:replace="~{fragments/card :: card(id='img-to-pdf', cardTitle=#{home.imageToPdf.title}, cardText=#{home.imageToPdf.desc}, cardLink='picture_as_pdf', toolIcon='picture_as_pdf', tags=#{imageToPdf.tags}, toolGroup='image')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/card :: card(id='file-to-pdf', cardTitle=#{home.fileToPDF.title}, cardText=#{home.fileToPDF.desc}, cardLink='file-to-pdf', toolIcon='draft', tags=#{fileToPDF.tags}, toolGroup='convert')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/card :: card(id='url-to-pdf', cardTitle=#{home.URLToPDF.title}, cardText=#{home.URLToPDF.desc}, cardLink='url-to-pdf', toolIcon='link', tags=#{URLToPDF.tags}, toolGroup='convert')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/card :: card(id='html-to-pdf', cardTitle=#{home.HTMLToPDF.title}, cardText=#{home.HTMLToPDF.desc}, cardLink='html-to-pdf', toolIcon='html', tags=#{HTMLToPDF.tags}, toolGroup='convert')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/card :: card(id='markdown-to-pdf', cardTitle=#{home.MarkdownToPDF.title}, cardText=#{home.MarkdownToPDF.desc}, cardLink='markdown-to-pdf', toolIcon='markdown', tags=#{MarkdownToPDF.tags}, toolGroup='convert')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/card :: card(id='book-to-pdf', cardTitle=#{home.BookToPDF.title}, cardText=#{home.BookToPDF.desc}, cardLink='book-to-pdf', toolIcon='book', tags=#{BookToPDF.tags}, toolGroup='convert')}">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="groupConvertFrom" class="feature-group-legacy">
|
||||
<div
|
||||
th:replace="~{fragments/featureGroupHeaderLegacy :: featureGroupHeader(groupTitle=#{navbar.sections.convertFrom})}">
|
||||
</div>
|
||||
<div class="feature-group-container">
|
||||
<div
|
||||
th:replace="~{fragments/card :: card(id='pdf-to-img', cardTitle=#{home.pdfToImage.title}, cardText=#{home.pdfToImage.desc}, cardLink='pdf-to-img', toolIcon='photo_library', tags=#{pdfToImage.tags}, toolGroup='image')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/card :: card(id='pdf-to-pdfa', cardTitle=#{home.pdfToPDFA.title}, cardText=#{home.pdfToPDFA.desc}, cardLink='pdf-to-pdfa', toolIcon='picture_as_pdf', tags=#{pdfToPDFA.tags}, toolGroup='convert')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/card :: card(id='pdf-to-word', cardTitle=#{home.PDFToWord.title}, cardText=#{home.PDFToWord.desc}, cardLink='pdf-to-word', toolIcon='description', tags=#{PDFToWord.tags}, toolGroup='word')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/card :: card(id='pdf-to-presentation', cardTitle=#{home.PDFToPresentation.title}, cardText=#{home.PDFToPresentation.desc}, cardLink='pdf-to-presentation', toolIcon='slideshow', tags=#{PDFToPresentation.tags}, toolGroup='ppt')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/card :: card(id='pdf-to-text', cardTitle=#{home.PDFToText.title}, cardText=#{home.PDFToText.desc}, cardLink='pdf-to-text', toolIcon='text_fields', tags=#{PDFToText.tags}, toolGroup='convert')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/card :: card(id='pdf-to-html', cardTitle=#{home.PDFToHTML.title}, cardText=#{home.PDFToHTML.desc}, cardLink='pdf-to-html', toolIcon='html', tags=#{PDFToHTML.tags}, toolGroup='convert')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/card :: card(id='pdf-to-xml', cardTitle=#{home.PDFToXML.title}, cardText=#{home.PDFToXML.desc}, cardLink='pdf-to-xml', toolIcon='code', tags=#{PDFToXML.tags}, toolGroup='convert')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/card :: card(id='pdf-to-csv', cardTitle=#{home.tableExtraxt.title}, cardText=#{home.tableExtraxt.desc}, cardLink='pdf-to-csv', toolIcon='csv', tags=#{tableExtraxt.tags}, toolGroup='convert')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/card :: card(id='pdf-to-book', cardTitle=#{home.PDFToBook.title}, cardText=#{home.PDFToBook.desc}, cardLink='pdf-to-book', toolIcon='book', tags=#{PDFToBook.tags}, toolGroup='convert')}">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="groupSecurity" class="feature-group-legacy">
|
||||
<div
|
||||
th:replace="~{fragments/featureGroupHeaderLegacy :: featureGroupHeader(groupTitle=#{navbar.sections.security})}">
|
||||
</div>
|
||||
<div class="feature-group-container">
|
||||
<div
|
||||
th:replace="~{fragments/card :: card(id='add-password', cardTitle=#{home.addPassword.title}, cardText=#{home.addPassword.desc}, cardLink='add-password', toolIcon='lock', tags=#{addPassword.tags}, toolGroup='security')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/card :: card(id='remove-password', cardTitle=#{home.removePassword.title}, cardText=#{home.removePassword.desc}, cardLink='remove-password', toolIcon='lock_open_right', tags=#{removePassword.tags}, toolGroup='security')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/card :: card(id='change-permissions', cardTitle=#{home.permissions.title}, cardText=#{home.permissions.desc}, cardLink='change-permissions', toolIcon='encrypted', tags=#{permissions.tags}, toolGroup='security')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/card :: card(id='sign', cardTitle=#{home.sign.title}, cardText=#{home.sign.desc}, cardLink='sign', toolIcon='signature', tags=#{sign.tags}, toolGroup='sign')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/card :: card(id='cert-sign', cardTitle=#{home.certSign.title}, cardText=#{home.certSign.desc}, cardLink='cert-sign', toolIcon='workspace_premium', tags=#{certSign.tags}, toolGroup='security')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/card :: card(id='validate-signature', cardTitle=#{home.validateSignature.title}, cardText=#{home.validateSignature.desc}, cardLink='validate-signature', toolIcon='verified', tags=#{validateSignature.tags}, toolGroup='security')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/card :: card(id='remove-cert-sign', cardTitle=#{home.removeCertSign.title}, cardText=#{home.removeCertSign.desc}, cardLink='remove-cert-sign', toolIcon='remove_moderator', tags=#{removeCertSign.tags}, toolGroup='security')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/card :: card(id='sanitize-pdf', cardTitle=#{home.sanitizePdf.title}, cardText=#{home.sanitizePdf.desc}, cardLink='sanitize-pdf', toolIcon='sanitizer', tags=#{sanitizePdf.tags}, toolGroup='security')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/card :: card(id='auto-redact', cardTitle=#{home.autoRedact.title}, cardText=#{home.autoRedact.desc}, cardLink='auto-redact', toolIcon='ink_eraser', tags=#{autoRedact.tags}, toolGroup='security')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/card :: card(id='redact', cardTitle=#{home.redact.title}, cardText=#{home.redact.desc}, cardLink='redact', toolIcon='playlist_remove', tags=#{redact.tags}, toolGroup='security')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/card :: card(id='stamp', cardTitle=#{home.AddStampRequest.title}, cardText=#{home.AddStampRequest.desc}, cardLink='stamp', toolIcon='approval', tags=#{AddStampRequest.tags}, toolGroup='security')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/card :: card(id='add-watermark', cardTitle=#{home.watermark.title}, cardText=#{home.watermark.desc}, cardLink='add-watermark', toolIcon='water_drop', tags=#{watermark.tags}, toolGroup='security')}">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="groupView" class="feature-group-legacy">
|
||||
<div th:replace="~{fragments/featureGroupHeaderLegacy :: featureGroupHeader(groupTitle=#{navbar.sections.edit})}">
|
||||
</div>
|
||||
<div class="feature-group-container">
|
||||
<div
|
||||
th:replace="~{fragments/card :: card(id='view-pdf', cardTitle=#{home.viewPdf.title}, cardText=#{home.viewPdf.desc}, cardLink='view-pdf', toolIcon='menu_book', tags=#{viewPdf.tags}, toolGroup='other')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/card :: card(id='add-page-numbers', cardTitle=#{home.add-page-numbers.title}, cardText=#{home.add-page-numbers.desc}, cardLink='add-page-numbers', toolIcon='123', tags=#{add-page-numbers.tags}, toolGroup='other')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/card :: card(id='add-image', cardTitle=#{home.addImage.title}, cardText=#{home.addImage.desc}, cardLink='add-image', toolIcon='add_photo_alternate', tags=#{addImage.tags}, toolGroup='other')}">
|
||||
</div>
|
||||
|
||||
<div
|
||||
th:replace="~{fragments/card :: card(id='change-metadata', cardTitle=#{home.changeMetadata.title}, cardText=#{home.changeMetadata.desc}, cardLink='change-metadata', toolIcon='assignment', tags=#{changeMetadata.tags}, toolGroup='other')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/card :: card(id='ocr-pdf', cardTitle=#{home.ocr.title}, cardText=#{home.ocr.desc}, cardLink='ocr-pdf', toolIcon='quick_reference_all', tags=#{ocr.tags}, toolGroup='other')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/card :: card(id='extract-images', cardTitle=#{home.extractImages.title}, cardText=#{home.extractImages.desc}, cardLink='extract-images', toolIcon='wallpaper', tags=#{extractImages.tags}, toolGroup='other')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/card :: card(id='flatten', cardTitle=#{home.flatten.title}, cardText=#{home.flatten.desc}, cardLink='flatten', toolIcon='layers_clear', tags=#{flatten.tags}, toolGroup='other')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/card :: card(id='remove-blanks', cardTitle=#{home.removeBlanks.title}, cardText=#{home.removeBlanks.desc}, cardLink='remove-blanks', toolIcon='scan_delete', tags=#{removeBlanks.tags}, toolGroup='other')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/card :: card(id='remove-annotations', cardTitle=#{home.removeAnnotations.title}, cardText=#{home.removeAnnotations.desc}, cardLink='remove-annotations', toolIcon='thread_unread', tags=#{removeAnnotations.tags}, toolGroup='other')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/card :: card(id='compare', cardTitle=#{home.compare.title}, cardText=#{home.compare.desc}, cardLink='compare', toolIcon='compare', tags=#{compare.tags}, toolGroup='other')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/card :: card(id='get-info-on-pdf', cardTitle=#{home.getPdfInfo.title}, cardText=#{home.getPdfInfo.desc}, cardLink='get-info-on-pdf', toolIcon='info', tags=#{getPdfInfo.tags}, toolGroup='other')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/card :: card(id='remove-image-pdf', cardTitle=#{home.removeImagePdf.title}, cardText=#{home.removeImagePdf.desc}, cardLink='remove-image-pdf', toolIcon='remove_selection', tags=#{removeImagePdf.tags}, toolGroup='other')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/card :: card(id='replace-color-pdf', cardTitle=#{home.replaceColorPdf.title}, cardText=#{home.replaceColorPdf.desc}, cardLink='replace-and-invert-color-pdf', toolIcon='format_color_fill', tags=#{replaceColorPdf.tags}, toolGroup='other')}">
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div id="groupAdvanced" class="feature-group-legacy">
|
||||
<div
|
||||
th:replace="~{fragments/featureGroupHeaderLegacy :: featureGroupHeader(groupTitle=#{navbar.sections.advance})}">
|
||||
</div>
|
||||
<div class="feature-group-container">
|
||||
<div
|
||||
th:replace="~{fragments/card :: card(id='pipeline', cardTitle=#{home.pipeline.title}, cardText=#{home.pipeline.desc}, cardLink='pipeline', toolIcon='family_history', tags=#{pipeline.tags}, toolGroup='advance')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/card :: card(id='adjust-contrast', cardTitle=#{home.adjust-contrast.title}, cardText=#{home.adjust-contrast.desc}, cardLink='adjust-contrast', toolIcon='palette', tags=#{adjust-contrast.tags}, toolGroup='advance')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/card :: card(id='compress-pdf', cardTitle=#{home.compressPdfs.title}, cardText=#{home.compressPdfs.desc}, cardLink='compress-pdf', toolIcon='zoom_in_map', tags=#{compressPdfs.tags}, toolGroup='advance')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/card :: card(id='extract-image-scans', cardTitle=#{home.ScannerImageSplit.title}, cardText=#{home.ScannerImageSplit.desc}, cardLink='extract-image-scans', toolIcon='scanner', tags=#{ScannerImageSplit.tags}, toolGroup='advance')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/card :: card(id='repair', cardTitle=#{home.repair.title}, cardText=#{home.repair.desc}, cardLink='repair', toolIcon='build', tags=#{repair.tags}, toolGroup='advance')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/card :: card(id='auto-rename', cardTitle=#{home.auto-rename.title}, cardText=#{home.auto-rename.desc}, cardLink='auto-rename', toolIcon='text_fields_alt', tags=#{auto-rename.tags}, toolGroup='advance')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/card :: card(id='auto-split-pdf', cardTitle=#{home.autoSplitPDF.title}, cardText=#{home.autoSplitPDF.desc}, cardLink='auto-split-pdf', toolIcon='cut', tags=#{autoSplitPDF.tags}, toolGroup='advance')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/card :: card(id='show-javascript', cardTitle=#{home.showJS.title}, cardText=#{home.showJS.desc}, cardLink='show-javascript', toolIcon='javascript', tags=#{showJS.tags}, toolGroup='advance')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/card :: card(id='split-by-size-or-count', cardTitle=#{home.autoSizeSplitPDF.title}, cardText=#{home.autoSizeSplitPDF.desc}, cardLink='split-by-size-or-count', toolIcon='vertical_split', tags=#{autoSizeSplitPDF.tags}, toolGroup='advance')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/card :: card(id='overlay-pdf', cardTitle=#{home.overlay-pdfs.title}, cardText=#{home.overlay-pdfs.desc}, cardLink='overlay-pdf', toolIcon='layers', tags=#{overlay-pdfs.tags}, toolGroup='advance')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/card :: card(id='split-pdf-by-sections', cardTitle=#{home.split-by-sections.title}, cardText=#{home.split-by-sections.desc}, cardLink='split-pdf-by-sections', toolIcon='grid_on', tags=#{split-by-sections.tags}, toolGroup='advance')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/card :: card(id='split-pdf-by-chapters', cardTitle=#{home.splitPdfByChapters.title}, cardText=#{home.splitPdfByChapters.desc}, cardLink='split-pdf-by-chapters', toolIcon='book', tags=#{splitPdfByChapters.tags}, toolGroup='advance')}">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<th:block th:insert="~{fragments/footer.html :: footer}"></th:block>
|
||||
</div>
|
||||
|
||||
|
||||
<!-- Survey Modal -->
|
||||
<div class="modal fade" id="surveyModal" tabindex="-1" role="dialog" aria-labelledby="surveyModalLabel"
|
||||
aria-hidden="true">
|
||||
<div class="modal-dialog modal-dialog-centered" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="surveyModalLabel" th:text="#{survey.title}">Stirling-PDF Survey</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<p><span th:text="#{survey.changes}">Stirling-PDF has changed since the last survey! To find out more please
|
||||
check our blog post here: </span><a href="https://www.stirlingpdf.com/blog/stirling-pdf-future"
|
||||
target="_blank"> Stirling PDF</a></p>
|
||||
|
||||
<p th:text="#{survey.changes2}">With these changes we are getting paid business support and funding</p>
|
||||
<p th:text="#{survey.please}">Please consider taking our survey!</p>
|
||||
<p th:text="#{survey.disabled}">Survey popup will be disabled in following updates but available at foot of
|
||||
page)</p>
|
||||
<a href="https://stirlingpdf.info/s/cm28y3niq000o56dv7liv8wsu" target="_blank" class="btn btn-primary"
|
||||
id="takeSurvey" th:text="#{survey.button}">Take Survey</a>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<div class="form-check mb-3">
|
||||
<input type="checkbox" id="dontShowAgain">
|
||||
<label for="dontShowAgain" th:text="#{survey.dontShowAgain}">Don't show again</label>
|
||||
</div>
|
||||
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal" th:text="#{close}">Close</button>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<!-- Analytics Modal -->
|
||||
<div class="modal fade" id="analyticsModal" tabindex="-1" role="dialog" aria-labelledby="analyticsModalLabel"
|
||||
aria-hidden="true" th:if="${@analyticsPrompt}">
|
||||
<div class="modal-dialog modal-dialog-centered" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="analyticsModalLabel" th:text="#{analytics.title}">Do you want make Stirling PDF
|
||||
better?</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<p th:text="#{analytics.paragraph1}">Stirling PDF has opt in analytics to help us improve the product. We do
|
||||
not track any personal information or file contents.</p>
|
||||
<p th:text="#{analytics.paragraph2}">Please consider enabling analytics to help Stirling-PDF grow and to allow
|
||||
us to understand our users better.</p>
|
||||
<p th:text="#{analytics.settings}">You can change the settings for analytics in the config/settings.yml file
|
||||
</p>
|
||||
</div>
|
||||
<div class="modal-footer justify-content-between">
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal" onclick="setAnalytics(false)"
|
||||
th:text="#{analytics.disable}">Disable analytics</button>
|
||||
<button type="button" class="btn btn-primary" th:text="#{analytics.enable}"
|
||||
onclick="setAnalytics(true)">Enable analytics</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<script th:src="@{'/js/fetch-utils.js'}"></script>
|
||||
<script th:inline="javascript">
|
||||
|
||||
/*<![CDATA[*/
|
||||
const analyticsPromptBoolean = /*[[${@analyticsPrompt}]]*/ false;
|
||||
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
if (analyticsPromptBoolean) {
|
||||
const analyticsModal = new bootstrap.Modal(document.getElementById('analyticsModal'));
|
||||
analyticsModal.show();
|
||||
}
|
||||
});
|
||||
/*]]>*/
|
||||
function setAnalytics(enabled) {
|
||||
fetchWithCsrf('api/v1/settings/update-enable-analytics', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify(enabled)
|
||||
})
|
||||
.then(response => {
|
||||
if (response.status === 200) {
|
||||
console.log('Analytics setting updated successfully');
|
||||
bootstrap.Modal.getInstance(document.getElementById('analyticsModal')).hide();
|
||||
} else if (response.status === 208) {
|
||||
console.log('Analytics setting has already been set. Please edit /config/settings.yml to change it.', response);
|
||||
alert('Analytics setting has already been set. Please edit /config/settings.yml to change it.');
|
||||
} else {
|
||||
throw new Error('Unexpected response status: ' + response.status);
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error updating analytics setting:', error);
|
||||
alert('An error occurred while updating the analytics setting. Please try again.');
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
document.addEventListener("DOMContentLoaded", function () {
|
||||
const surveyVersion = "2.0";
|
||||
const modal = new bootstrap.Modal(document.getElementById('surveyModal'));
|
||||
const dontShowAgain = document.getElementById('dontShowAgain');
|
||||
const takeSurveyButton = document.getElementById('takeSurvey');
|
||||
|
||||
const viewThresholds = [5, 10, 15, 22, 30, 50, 75, 100, 150, 200];
|
||||
|
||||
// Check if survey version changed and reset page views if it did
|
||||
const storedVersion = localStorage.getItem('surveyVersion');
|
||||
if (storedVersion && storedVersion !== surveyVersion) {
|
||||
localStorage.setItem('pageViews', '0');
|
||||
}
|
||||
|
||||
let pageViews = parseInt(localStorage.getItem('pageViews') || '0');
|
||||
|
||||
pageViews++;
|
||||
localStorage.setItem('pageViews', pageViews.toString());
|
||||
|
||||
function shouldShowSurvey() {
|
||||
if (localStorage.getItem('dontShowSurvey') === 'true' ||
|
||||
localStorage.getItem('surveyTaken') === 'true') {
|
||||
return false;
|
||||
}
|
||||
|
||||
// If survey version changed and we hit a threshold, show the survey
|
||||
if (localStorage.getItem('surveyVersion') !== surveyVersion &&
|
||||
viewThresholds.includes(pageViews)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return viewThresholds.includes(pageViews);
|
||||
}
|
||||
|
||||
if (shouldShowSurvey()) {
|
||||
modal.show();
|
||||
}
|
||||
|
||||
dontShowAgain.addEventListener('change', function () {
|
||||
if (this.checked) {
|
||||
localStorage.setItem('dontShowSurvey', 'true');
|
||||
localStorage.setItem('surveyVersion', surveyVersion);
|
||||
} else {
|
||||
localStorage.removeItem('dontShowSurvey');
|
||||
localStorage.removeItem('surveyVersion');
|
||||
}
|
||||
});
|
||||
|
||||
takeSurveyButton.addEventListener('click', function () {
|
||||
localStorage.setItem('surveyTaken', 'true');
|
||||
localStorage.setItem('surveyVersion', surveyVersion);
|
||||
modal.hide();
|
||||
});
|
||||
|
||||
if (localStorage.getItem('dontShowSurvey')) {
|
||||
modal.hide();
|
||||
}
|
||||
});
|
||||
|
||||
function setAsDefault(value) {
|
||||
localStorage.setItem('defaultView', value);
|
||||
console.log(`Default view set to: ${value}`);
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
@ -10,42 +10,99 @@
|
||||
<div id="page-container">
|
||||
<div id="content-wrap">
|
||||
<th:block th:insert="~{fragments/navbar.html :: navbar}"></th:block>
|
||||
<!-- Jumbotron -->
|
||||
<div class="p-5 rounded d-none d-md-block" id="jumbotron">
|
||||
<div class="container">
|
||||
<h1 class="display-4 fw-normal" th:text="${@appName}"></h1>
|
||||
<p class="lead fs-4"
|
||||
th:text="${@homeText != 'null' and @homeText != null and @homeText != ''} ? ${@homeText} : #{home.desc}">
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<br class="d-md-none">
|
||||
<!-- Features -->
|
||||
<script th:src="@{'/js/homecard.js'}"></script>
|
||||
<div class=" container">
|
||||
<br>
|
||||
<span class="material-symbols-rounded search-icon">
|
||||
search
|
||||
</span>
|
||||
<input type="text" id="searchBar" onkeyup="filterCards()" th:placeholder="#{home.searchBar}" autofocus>
|
||||
<div style="
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;">
|
||||
|
||||
<div id="filtersContainer">
|
||||
<span class="material-symbols-rounded filter-button" onclick="toggleFavoritesOnly()">
|
||||
star
|
||||
</span>
|
||||
<span class="material-symbols-rounded filter-button" onclick="expandCollapseAll(true)">
|
||||
expand_all
|
||||
</span>
|
||||
<span class="material-symbols-rounded filter-button" onclick="expandCollapseAll(false)">
|
||||
collapse_all
|
||||
</span>
|
||||
<span class="material-symbols-rounded filter-button hidden" onclick="switchViewMode()">
|
||||
dashboard
|
||||
</span>
|
||||
<div>
|
||||
<br>
|
||||
<div style="justify-content: center; display: flex;">
|
||||
<div style="margin:0 3rem">
|
||||
<div>
|
||||
<div style="display:flex; flex-direction: column; justify-content: center; width:100%; margin-bottom:1rem">
|
||||
<div style="width:fit-content; margin: 0 auto; padding: 0 3rem">
|
||||
<p class="lead fs-4"
|
||||
th:text="${@homeText != 'null' and @homeText != null and @homeText != ''} ? ${@homeText} : #{home.desc}">
|
||||
</p>
|
||||
</div>
|
||||
<div id="groupRecent" style="width: fit-content; margin: 0 auto">
|
||||
<div th:replace="~{fragments/featureGroupHeader :: featureGroupHeader(groupTitle=#{navbar.recent})}">
|
||||
</div>
|
||||
<div class="recent-features">
|
||||
<div class="newfeature"
|
||||
th:include="~{fragments/navbarEntryCustom :: navbarEntry('redact', '/images/redact-manual.svg#icon-redact-manual', 'home.redact.title', 'home.redact.desc', 'redact.tags', 'security')}">
|
||||
</div>
|
||||
<div class="newfeature"
|
||||
th:include="~{fragments/navbarEntry :: navbarEntry ('multi-tool', 'construction', 'home.multiTool.title', 'home.multiTool.desc', 'multiTool.tags', 'organize')}">
|
||||
</div>
|
||||
<div class="newfeature"
|
||||
th:include="~{fragments/navbarEntry :: navbarEntry('validate-signature', 'verified', 'home.validateSignature.title', 'home.validateSignature.desc', 'validateSignature.tags', 'security')}">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<span class="material-symbols-rounded search-icon">
|
||||
search
|
||||
</span>
|
||||
<input type="text" id="searchBar" onkeyup="filterCards()" th:placeholder="#{home.searchBar}" autofocus>
|
||||
|
||||
<div style="display: flex;">
|
||||
<div
|
||||
style="height:2.5rem; display: flex; align-items: center; cursor: pointer; justify-content: center;">
|
||||
<label for="sort-options">Sort by:</label>
|
||||
<select id="sort-options" style="border:none;">
|
||||
<option value="alphabetical" th:text="#{home.alphabetical}"> </option>
|
||||
<!-- <option value="personal">Your most used</option> -->
|
||||
<option value="global" th:text="#{home.globalPopularity}"></option>
|
||||
<!-- <option value="server">Popularity in organisation</option> -->
|
||||
</select>
|
||||
</div>
|
||||
<div
|
||||
style="display: flex; margin-left:2rem;align-items: center; flex-wrap: wrap; align-content: flex-start; width: fit-content; max-width: 100%; gap:3rem; justify-content: center;">
|
||||
<div th:title="#{home.setFavorites}" style="display: flex; align-items: center; cursor: pointer;" onclick="toggleFavoritesMode()">
|
||||
<span class="material-symbols-rounded toggle-favourites"
|
||||
style="font-size: 2rem; margin-left: 0.2rem;">
|
||||
star
|
||||
</span>
|
||||
</div>
|
||||
<div onclick="toggleFavoritesView()" th:title="#{home.hideFavorites}" id="favouritesVisibility"
|
||||
style="display: flex; align-items: center; cursor: pointer;">
|
||||
<span id="toggle-favourites-icon" class="material-symbols-rounded toggle-favourites"
|
||||
style="font-size: 2rem; margin-left: 0.2rem;">
|
||||
visibility
|
||||
</span>
|
||||
</div>
|
||||
<a href="home" onclick="setAsDefault('home-legacy')" th:title="#{home.legacyHomepage}"
|
||||
style="text-decoration: none; color: inherit; cursor: pointer; display: flex; align-items: center;">
|
||||
</span>
|
||||
<span class="material-symbols-rounded toggle-favourites"
|
||||
style="font-size: 2rem; margin-left: 0.2rem;">
|
||||
home
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="features-container">
|
||||
|
||||
<div>
|
||||
</div>
|
||||
<div class="features-container" style=" border-top: 1px;
|
||||
border-top-style: solid;
|
||||
border-color: var(--md-nav-color-on-seperator);
|
||||
margin-top: 1rem;
|
||||
">
|
||||
<div th:if="${@shouldShow}" class="feature-card favorite update-notice" id="update-link"
|
||||
style="display: none;">
|
||||
<a href="https://github.com/Stirling-Tools/Stirling-PDF/releases" target="_blank" rel="noopener">
|
||||
@ -60,278 +117,16 @@
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div id="groupFavorites" class="feature-group">
|
||||
<div th:replace="~{fragments/featureGroupHeader :: featureGroupHeader(groupTitle=#{navbar.favorite})}">
|
||||
</div>
|
||||
<div class="feature-group-container">
|
||||
<div class="feature-rows">
|
||||
<div id="groupFavorites" class="feature-group">
|
||||
<div th:replace="~{fragments/featureGroupHeader :: featureGroupHeader(groupTitle=#{navbar.favorite})}">
|
||||
</div>
|
||||
<div class="nav-group-container">
|
||||
</div>
|
||||
</div>
|
||||
<th:block th:insert="~{fragments/navElements.html :: navElements}"></th:block>
|
||||
</div>
|
||||
|
||||
|
||||
<div id="popularTools" class="feature-group">
|
||||
<div
|
||||
th:replace="~{fragments/featureGroupHeader :: featureGroupHeader(groupTitle=#{navbar.sections.popular})}">
|
||||
</div>
|
||||
<div class="feature-group-container">
|
||||
<div
|
||||
th:replace="~{fragments/card :: card(id='view-pdf', cardTitle=#{home.viewPdf.title}, cardText=#{home.viewPdf.desc}, cardLink='view-pdf', toolIcon='menu_book', tags=#{viewPdf.tags}, toolGroup='other')}">
|
||||
</div>
|
||||
|
||||
<div
|
||||
th:replace="~{fragments/card :: card(id='multi-tool', cardTitle=#{home.multiTool.title}, cardText=#{home.multiTool.desc}, cardLink='multi-tool', toolIcon='construction', tags=#{multiTool.tags}, toolGroup='organize')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/card :: card(id='pipeline', cardTitle=#{home.pipeline.title}, cardText=#{home.pipeline.desc}, cardLink='pipeline', toolIcon='family_history', tags=#{pipeline.tags}, toolGroup='advance')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/card :: card(id='compress-pdf', cardTitle=#{home.compressPdfs.title}, cardText=#{home.compressPdfs.desc}, cardLink='compress-pdf', toolIcon='zoom_in_map', tags=#{compressPdfs.tags}, toolGroup='advance')}">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
<div id="groupOrganize" class="feature-group">
|
||||
<div
|
||||
th:replace="~{fragments/featureGroupHeader :: featureGroupHeader(groupTitle=#{navbar.sections.organize})}">
|
||||
</div>
|
||||
<div class="feature-group-container">
|
||||
<div
|
||||
th:replace="~{fragments/card :: card(id='multi-tool', cardTitle=#{home.multiTool.title}, cardText=#{home.multiTool.desc}, cardLink='multi-tool', toolIcon='construction', tags=#{multiTool.tags}, toolGroup='organize')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/card :: card(id='merge-pdfs', cardTitle=#{home.merge.title}, cardText=#{home.merge.desc}, cardLink='merge-pdfs', toolIcon='add_to_photos', tags=#{merge.tags}, toolGroup='organize')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/card :: card(id='split-pdfs', cardTitle=#{home.split.title}, cardText=#{home.split.desc}, cardLink='split-pdfs', toolIcon='cut', tags=#{split.tags}, toolGroup='organize')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/card :: card(id='rotate-pdf', cardTitle=#{home.rotate.title}, cardText=#{home.rotate.desc}, cardLink='rotate-pdf', toolIcon='rotate_right', tags=#{rotate.tags}, toolGroup='organize')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/card :: card(id='crop', cardTitle=#{home.crop.title}, cardText=#{home.crop.desc}, cardLink='crop', toolIcon='crop', tags=#{crop.tags}, toolGroup='organize')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/card :: card(id='pdf-organizer', cardTitle=#{home.pdfOrganiser.title}, cardText=#{home.pdfOrganiser.desc}, cardLink='pdf-organizer', toolIcon='format_list_bulleted', tags=#{pdfOrganiser.tags}, toolGroup='organize')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/card :: card(id='remove-pages', cardTitle=#{home.removePages.title}, cardText=#{home.removePages.desc}, cardLink='remove-pages', toolIcon='delete', tags=#{removePages.tags}, toolGroup='organize')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/card :: card(id='multi-page-layout', cardTitle=#{home.pageLayout.title}, cardText=#{home.pageLayout.desc}, cardLink='multi-page-layout', toolIcon='dashboard', tags=#{pageLayout.tags}, toolGroup='organize')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/card :: card(id='scale-pages', cardTitle=#{home.scalePages.title}, cardText=#{home.scalePages.desc}, cardLink='scale-pages', toolIcon='fullscreen', tags=#{scalePages.tags}, toolGroup='organize')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/card :: card(id='extract-page', cardTitle=#{home.extractPage.title}, cardText=#{home.extractPage.desc}, cardLink='extract-page', toolIcon='upload', tags=#{extractPage.tags}, toolGroup='organize')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/card :: card(id='pdf-to-single-page', cardTitle=#{home.PdfToSinglePage.title}, cardText=#{home.PdfToSinglePage.desc}, cardLink='pdf-to-single-page', toolIcon='looks_one', tags=#{PdfToSinglePage.tags}, toolGroup='organize')}">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="groupConvertTo" class="feature-group">
|
||||
<div
|
||||
th:replace="~{fragments/featureGroupHeader :: featureGroupHeader(groupTitle=#{navbar.sections.convertTo})}">
|
||||
</div>
|
||||
<div class="feature-group-container">
|
||||
<div
|
||||
th:replace="~{fragments/card :: card(id='img-to-pdf', cardTitle=#{home.imageToPdf.title}, cardText=#{home.imageToPdf.desc}, cardLink='img-to-pdf', toolIcon='picture_as_pdf', tags=#{imageToPdf.tags}, toolGroup='image')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/card :: card(id='file-to-pdf', cardTitle=#{home.fileToPDF.title}, cardText=#{home.fileToPDF.desc}, cardLink='file-to-pdf', toolIcon='draft', tags=#{fileToPDF.tags}, toolGroup='convert')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/card :: card(id='url-to-pdf', cardTitle=#{home.URLToPDF.title}, cardText=#{home.URLToPDF.desc}, cardLink='url-to-pdf', toolIcon='link', tags=#{URLToPDF.tags}, toolGroup='convert')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/card :: card(id='html-to-pdf', cardTitle=#{home.HTMLToPDF.title}, cardText=#{home.HTMLToPDF.desc}, cardLink='html-to-pdf', toolIcon='html', tags=#{HTMLToPDF.tags}, toolGroup='convert')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/card :: card(id='markdown-to-pdf', cardTitle=#{home.MarkdownToPDF.title}, cardText=#{home.MarkdownToPDF.desc}, cardLink='markdown-to-pdf', toolIcon='markdown', tags=#{MarkdownToPDF.tags}, toolGroup='convert')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/card :: card(id='book-to-pdf', cardTitle=#{home.BookToPDF.title}, cardText=#{home.BookToPDF.desc}, cardLink='book-to-pdf', toolIcon='book', tags=#{BookToPDF.tags}, toolGroup='convert')}">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="groupConvertFrom" class="feature-group">
|
||||
<div
|
||||
th:replace="~{fragments/featureGroupHeader :: featureGroupHeader(groupTitle=#{navbar.sections.convertFrom})}">
|
||||
</div>
|
||||
<div class="feature-group-container">
|
||||
<div
|
||||
th:replace="~{fragments/card :: card(id='pdf-to-img', cardTitle=#{home.pdfToImage.title}, cardText=#{home.pdfToImage.desc}, cardLink='pdf-to-img', toolIcon='photo_library', tags=#{pdfToImage.tags}, toolGroup='image')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/card :: card(id='pdf-to-pdfa', cardTitle=#{home.pdfToPDFA.title}, cardText=#{home.pdfToPDFA.desc}, cardLink='pdf-to-pdfa', toolIcon='picture_as_pdf', tags=#{pdfToPDFA.tags}, toolGroup='convert')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/card :: card(id='pdf-to-word', cardTitle=#{home.PDFToWord.title}, cardText=#{home.PDFToWord.desc}, cardLink='pdf-to-word', toolIcon='description', tags=#{PDFToWord.tags}, toolGroup='word')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/card :: card(id='pdf-to-presentation', cardTitle=#{home.PDFToPresentation.title}, cardText=#{home.PDFToPresentation.desc}, cardLink='pdf-to-presentation', toolIcon='slideshow', tags=#{PDFToPresentation.tags}, toolGroup='ppt')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/card :: card(id='pdf-to-text', cardTitle=#{home.PDFToText.title}, cardText=#{home.PDFToText.desc}, cardLink='pdf-to-text', toolIcon='text_fields', tags=#{PDFToText.tags}, toolGroup='convert')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/card :: card(id='pdf-to-html', cardTitle=#{home.PDFToHTML.title}, cardText=#{home.PDFToHTML.desc}, cardLink='pdf-to-html', toolIcon='html', tags=#{PDFToHTML.tags}, toolGroup='convert')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/card :: card(id='pdf-to-xml', cardTitle=#{home.PDFToXML.title}, cardText=#{home.PDFToXML.desc}, cardLink='pdf-to-xml', toolIcon='code', tags=#{PDFToXML.tags}, toolGroup='convert')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/card :: card(id='pdf-to-csv', cardTitle=#{home.tableExtraxt.title}, cardText=#{home.tableExtraxt.desc}, cardLink='pdf-to-csv', toolIcon='csv', tags=#{tableExtraxt.tags}, toolGroup='convert')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/card :: card(id='pdf-to-book', cardTitle=#{home.PDFToBook.title}, cardText=#{home.PDFToBook.desc}, cardLink='pdf-to-book', toolIcon='book', tags=#{PDFToBook.tags}, toolGroup='convert')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/card :: card(id='pdf-to-markdown', cardTitle=#{home.PDFToMarkdown.title}, cardText=#{home.PDFToMarkdown.desc}, cardLink='pdf-to-markdown', toolIcon='markdown_copy', tags=#{PDFToMarkdown.tags}, toolGroup='convert')}">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="groupSecurity" class="feature-group">
|
||||
<div
|
||||
th:replace="~{fragments/featureGroupHeader :: featureGroupHeader(groupTitle=#{navbar.sections.security})}">
|
||||
</div>
|
||||
<div class="feature-group-container">
|
||||
<div
|
||||
th:replace="~{fragments/card :: card(id='add-password', cardTitle=#{home.addPassword.title}, cardText=#{home.addPassword.desc}, cardLink='add-password', toolIcon='lock', tags=#{addPassword.tags}, toolGroup='security')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/card :: card(id='remove-password', cardTitle=#{home.removePassword.title}, cardText=#{home.removePassword.desc}, cardLink='remove-password', toolIcon='lock_open_right', tags=#{removePassword.tags}, toolGroup='security')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/card :: card(id='change-permissions', cardTitle=#{home.permissions.title}, cardText=#{home.permissions.desc}, cardLink='change-permissions', toolIcon='encrypted', tags=#{permissions.tags}, toolGroup='security')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/card :: card(id='sign', cardTitle=#{home.sign.title}, cardText=#{home.sign.desc}, cardLink='sign', toolIcon='signature', tags=#{sign.tags}, toolGroup='sign')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/card :: card(id='cert-sign', cardTitle=#{home.certSign.title}, cardText=#{home.certSign.desc}, cardLink='cert-sign', toolIcon='workspace_premium', tags=#{certSign.tags}, toolGroup='security')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/card :: card(id='validate-signature', cardTitle=#{home.validateSignature.title}, cardText=#{home.validateSignature.desc}, cardLink='validate-signature', toolIcon='verified', tags=#{validateSignature.tags}, toolGroup='security')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/card :: card(id='remove-cert-sign', cardTitle=#{home.removeCertSign.title}, cardText=#{home.removeCertSign.desc}, cardLink='remove-cert-sign', toolIcon='remove_moderator', tags=#{removeCertSign.tags}, toolGroup='security')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/card :: card(id='sanitize-pdf', cardTitle=#{home.sanitizePdf.title}, cardText=#{home.sanitizePdf.desc}, cardLink='sanitize-pdf', toolIcon='sanitizer', tags=#{sanitizePdf.tags}, toolGroup='security')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/card :: card(id='auto-redact', cardTitle=#{home.autoRedact.title}, cardText=#{home.autoRedact.desc}, cardLink='auto-redact', toolIcon='ink_eraser', tags=#{autoRedact.tags}, toolGroup='security')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/card :: card(id='redact', cardTitle=#{home.redact.title}, cardText=#{home.redact.desc}, cardLink='redact', toolIcon='playlist_remove', tags=#{redact.tags}, toolGroup='security')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/card :: card(id='stamp', cardTitle=#{home.AddStampRequest.title}, cardText=#{home.AddStampRequest.desc}, cardLink='stamp', toolIcon='approval', tags=#{AddStampRequest.tags}, toolGroup='security')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/card :: card(id='add-watermark', cardTitle=#{home.watermark.title}, cardText=#{home.watermark.desc}, cardLink='add-watermark', toolIcon='water_drop', tags=#{watermark.tags}, toolGroup='security')}">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="groupView" class="feature-group">
|
||||
<div th:replace="~{fragments/featureGroupHeader :: featureGroupHeader(groupTitle=#{navbar.sections.edit})}">
|
||||
</div>
|
||||
<div class="feature-group-container">
|
||||
<div
|
||||
th:replace="~{fragments/card :: card(id='view-pdf', cardTitle=#{home.viewPdf.title}, cardText=#{home.viewPdf.desc}, cardLink='view-pdf', toolIcon='menu_book', tags=#{viewPdf.tags}, toolGroup='other')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/card :: card(id='add-page-numbers', cardTitle=#{home.add-page-numbers.title}, cardText=#{home.add-page-numbers.desc}, cardLink='add-page-numbers', toolIcon='123', tags=#{add-page-numbers.tags}, toolGroup='other')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/card :: card(id='add-image', cardTitle=#{home.addImage.title}, cardText=#{home.addImage.desc}, cardLink='add-image', toolIcon='add_photo_alternate', tags=#{addImage.tags}, toolGroup='other')}">
|
||||
</div>
|
||||
|
||||
<div
|
||||
th:replace="~{fragments/card :: card(id='change-metadata', cardTitle=#{home.changeMetadata.title}, cardText=#{home.changeMetadata.desc}, cardLink='change-metadata', toolIcon='assignment', tags=#{changeMetadata.tags}, toolGroup='other')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/card :: card(id='ocr-pdf', cardTitle=#{home.ocr.title}, cardText=#{home.ocr.desc}, cardLink='ocr-pdf', toolIcon='quick_reference_all', tags=#{ocr.tags}, toolGroup='other')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/card :: card(id='extract-images', cardTitle=#{home.extractImages.title}, cardText=#{home.extractImages.desc}, cardLink='extract-images', toolIcon='wallpaper', tags=#{extractImages.tags}, toolGroup='other')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/card :: card(id='flatten', cardTitle=#{home.flatten.title}, cardText=#{home.flatten.desc}, cardLink='flatten', toolIcon='layers_clear', tags=#{flatten.tags}, toolGroup='other')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/card :: card(id='remove-blanks', cardTitle=#{home.removeBlanks.title}, cardText=#{home.removeBlanks.desc}, cardLink='remove-blanks', toolIcon='scan_delete', tags=#{removeBlanks.tags}, toolGroup='other')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/card :: card(id='remove-annotations', cardTitle=#{home.removeAnnotations.title}, cardText=#{home.removeAnnotations.desc}, cardLink='remove-annotations', toolIcon='thread_unread', tags=#{removeAnnotations.tags}, toolGroup='other')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/card :: card(id='compare', cardTitle=#{home.compare.title}, cardText=#{home.compare.desc}, cardLink='compare', toolIcon='compare', tags=#{compare.tags}, toolGroup='other')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/card :: card(id='get-info-on-pdf', cardTitle=#{home.getPdfInfo.title}, cardText=#{home.getPdfInfo.desc}, cardLink='get-info-on-pdf', toolIcon='info', tags=#{getPdfInfo.tags}, toolGroup='other')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/card :: card(id='remove-image-pdf', cardTitle=#{home.removeImagePdf.title}, cardText=#{home.removeImagePdf.desc}, cardLink='remove-image-pdf', toolIcon='remove_selection', tags=#{removeImagePdf.tags}, toolGroup='other')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/card :: card(id='replace-color-pdf', cardTitle=#{home.replaceColorPdf.title}, cardText=#{home.replaceColorPdf.desc}, cardLink='replace-and-invert-color-pdf', toolIcon='format_color_fill', tags=#{replaceColorPdf.tags}, toolGroup='other')}">
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div id="groupAdvanced" class="feature-group">
|
||||
<div
|
||||
th:replace="~{fragments/featureGroupHeader :: featureGroupHeader(groupTitle=#{navbar.sections.advance})}">
|
||||
</div>
|
||||
<div class="feature-group-container">
|
||||
<div
|
||||
th:replace="~{fragments/card :: card(id='pipeline', cardTitle=#{home.pipeline.title}, cardText=#{home.pipeline.desc}, cardLink='pipeline', toolIcon='family_history', tags=#{pipeline.tags}, toolGroup='advance')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/card :: card(id='adjust-contrast', cardTitle=#{home.adjust-contrast.title}, cardText=#{home.adjust-contrast.desc}, cardLink='adjust-contrast', toolIcon='palette', tags=#{adjust-contrast.tags}, toolGroup='advance')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/card :: card(id='compress-pdf', cardTitle=#{home.compressPdfs.title}, cardText=#{home.compressPdfs.desc}, cardLink='compress-pdf', toolIcon='zoom_in_map', tags=#{compressPdfs.tags}, toolGroup='advance')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/card :: card(id='extract-image-scans', cardTitle=#{home.ScannerImageSplit.title}, cardText=#{home.ScannerImageSplit.desc}, cardLink='extract-image-scans', toolIcon='scanner', tags=#{ScannerImageSplit.tags}, toolGroup='advance')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/card :: card(id='repair', cardTitle=#{home.repair.title}, cardText=#{home.repair.desc}, cardLink='repair', toolIcon='build', tags=#{repair.tags}, toolGroup='advance')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/card :: card(id='auto-rename', cardTitle=#{home.auto-rename.title}, cardText=#{home.auto-rename.desc}, cardLink='auto-rename', toolIcon='text_fields_alt', tags=#{auto-rename.tags}, toolGroup='advance')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/card :: card(id='auto-split-pdf', cardTitle=#{home.autoSplitPDF.title}, cardText=#{home.autoSplitPDF.desc}, cardLink='auto-split-pdf', toolIcon='cut', tags=#{autoSplitPDF.tags}, toolGroup='advance')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/card :: card(id='show-javascript', cardTitle=#{home.showJS.title}, cardText=#{home.showJS.desc}, cardLink='show-javascript', toolIcon='javascript', tags=#{showJS.tags}, toolGroup='advance')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/card :: card(id='split-by-size-or-count', cardTitle=#{home.autoSizeSplitPDF.title}, cardText=#{home.autoSizeSplitPDF.desc}, cardLink='split-by-size-or-count', toolIcon='vertical_split', tags=#{autoSizeSplitPDF.tags}, toolGroup='advance')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/card :: card(id='overlay-pdf', cardTitle=#{home.overlay-pdfs.title}, cardText=#{home.overlay-pdfs.desc}, cardLink='overlay-pdf', toolIcon='layers', tags=#{overlay-pdfs.tags}, toolGroup='advance')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/card :: card(id='split-pdf-by-sections', cardTitle=#{home.split-by-sections.title}, cardText=#{home.split-by-sections.desc}, cardLink='split-pdf-by-sections', toolIcon='grid_on', tags=#{split-by-sections.tags}, toolGroup='advance')}">
|
||||
</div>
|
||||
<div
|
||||
th:replace="~{fragments/card :: card(id='split-pdf-by-chapters', cardTitle=#{home.splitPdfByChapters.title}, cardText=#{home.splitPdfByChapters.desc}, cardLink='split-pdf-by-chapters', toolIcon='book', tags=#{splitPdfByChapters.tags}, toolGroup='advance')}">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -403,108 +198,25 @@
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<script th:src="@{'/js/fetch-utils.js'}"></script>
|
||||
<script th:inline="javascript">
|
||||
|
||||
/*<![CDATA[*/
|
||||
const analyticsPromptBoolean = /*[[${@analyticsPrompt}]]*/ false;
|
||||
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
if (analyticsPromptBoolean) {
|
||||
const analyticsModal = new bootstrap.Modal(document.getElementById('analyticsModal'));
|
||||
analyticsModal.show();
|
||||
}
|
||||
});
|
||||
/*]]>*/
|
||||
function setAnalytics(enabled) {
|
||||
fetchWithCsrf('api/v1/settings/update-enable-analytics', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify(enabled)
|
||||
})
|
||||
.then(response => {
|
||||
if (response.status === 200) {
|
||||
console.log('Analytics setting updated successfully');
|
||||
bootstrap.Modal.getInstance(document.getElementById('analyticsModal')).hide();
|
||||
} else if (response.status === 208) {
|
||||
console.log('Analytics setting has already been set. Please edit /config/settings.yml to change it.', response);
|
||||
alert('Analytics setting has already been set. Please edit /config/settings.yml to change it.');
|
||||
} else {
|
||||
throw new Error('Unexpected response status: ' + response.status);
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error updating analytics setting:', error);
|
||||
alert('An error occurred while updating the analytics setting. Please try again.');
|
||||
});
|
||||
<style>
|
||||
.favorite-icon {
|
||||
cursor: pointer;
|
||||
width: 0rem;
|
||||
font-size: 2rem;
|
||||
}
|
||||
|
||||
.toggle-favourites {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
document.addEventListener("DOMContentLoaded", function () {
|
||||
const surveyVersion = "2.0";
|
||||
const modal = new bootstrap.Modal(document.getElementById('surveyModal'));
|
||||
const dontShowAgain = document.getElementById('dontShowAgain');
|
||||
const takeSurveyButton = document.getElementById('takeSurvey');
|
||||
|
||||
const viewThresholds = [5, 10, 15, 22, 30, 50, 75, 100, 150, 200];
|
||||
|
||||
// Check if survey version changed and reset page views if it did
|
||||
const storedVersion = localStorage.getItem('surveyVersion');
|
||||
if (storedVersion && storedVersion !== surveyVersion) {
|
||||
localStorage.setItem('pageViews', '0');
|
||||
}
|
||||
|
||||
let pageViews = parseInt(localStorage.getItem('pageViews') || '0');
|
||||
|
||||
pageViews++;
|
||||
localStorage.setItem('pageViews', pageViews.toString());
|
||||
|
||||
function shouldShowSurvey() {
|
||||
if (localStorage.getItem('dontShowSurvey') === 'true' ||
|
||||
localStorage.getItem('surveyTaken') === 'true') {
|
||||
return false;
|
||||
}
|
||||
|
||||
// If survey version changed and we hit a threshold, show the survey
|
||||
if (localStorage.getItem('surveyVersion') !== surveyVersion &&
|
||||
viewThresholds.includes(pageViews)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return viewThresholds.includes(pageViews);
|
||||
}
|
||||
|
||||
if (shouldShowSurvey()) {
|
||||
modal.show();
|
||||
}
|
||||
|
||||
dontShowAgain.addEventListener('change', function () {
|
||||
if (this.checked) {
|
||||
localStorage.setItem('dontShowSurvey', 'true');
|
||||
localStorage.setItem('surveyVersion', surveyVersion);
|
||||
} else {
|
||||
localStorage.removeItem('dontShowSurvey');
|
||||
localStorage.removeItem('surveyVersion');
|
||||
}
|
||||
});
|
||||
|
||||
takeSurveyButton.addEventListener('click', function () {
|
||||
localStorage.setItem('surveyTaken', 'true');
|
||||
localStorage.setItem('surveyVersion', surveyVersion);
|
||||
modal.hide();
|
||||
});
|
||||
|
||||
if (localStorage.getItem('dontShowSurvey')) {
|
||||
modal.hide();
|
||||
}
|
||||
});
|
||||
.toggle-favourites.active {
|
||||
color: gold;
|
||||
}
|
||||
</style>
|
||||
<script th:src="@{'/js/fetch-utils.js'}">
|
||||
window.analyticsPromptBoolean = /*[[${@analyticsPrompt}]]*/ false;
|
||||
</script>
|
||||
<script th:src="@{'/js/pages/home.js'}"></script>
|
||||
|
||||
|
||||
</body>
|
||||
|
@ -34,7 +34,7 @@
|
||||
</div>
|
||||
|
||||
<div class="draggable-buttons-box ignore-rtl">
|
||||
<button class="btn btn-outline-secondary"
|
||||
<button class="btn btn-outline-secondary" th:title="#{sign.delete}"
|
||||
onclick="DraggableUtils.deleteDraggableCanvas(DraggableUtils.getLastInteracted())"
|
||||
style="color: #C02223; border-color: #C02223; background-color: rgba(255, 0, 0, 0.1);">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-trash"
|
||||
@ -44,14 +44,12 @@
|
||||
<path
|
||||
d="M14.5 3a1 1 0 0 1-1 1H13v9a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V4h-.5a1 1 0 0 1-1-1V2a1 1 0 0 1 1-1H6a1 1 0 0 1 1-1h2a1 1 0 0 1 1 1h3.5a1 1 0 0 1 1 1v1ZM4.118 4 4 4.059V13a1 1 0 0 0 1 1h6a1 1 0 0 0 1-1V4.059L11.882 4H4.118ZM2.5 3h11V2h-11v1Z" />
|
||||
</svg>
|
||||
<span class="btn-tooltip" th:text="#{sign.delete}"></span>
|
||||
</button>
|
||||
<button class="btn btn-outline-secondary"
|
||||
<button class="btn btn-outline-secondary" th:title="#{sign.addToAll}"
|
||||
onclick="DraggableUtils.addAllPagesDraggableCanvas(DraggableUtils.getLastInteracted())">
|
||||
<span class="material-symbols-rounded">
|
||||
content_copy
|
||||
</span>
|
||||
<span class="btn-tooltip" th:text="#{sign.addToAll}"></span>
|
||||
</button>
|
||||
<div id="rotation-controls" class="align-items-center" style="display: none;">
|
||||
<div class="input-with-icon">
|
||||
@ -62,49 +60,44 @@
|
||||
style="width: 6rem" />
|
||||
</div>
|
||||
</div>
|
||||
<button id="ratioToggleBtn" class="btn btn-outline-secondary"
|
||||
<button id="ratioToggleBtn" th:title="#{sign.maintainRatio}" class="btn btn-outline-secondary"
|
||||
onclick="DraggableUtils.toggleMaintainRatio()">
|
||||
<span class="material-symbols-rounded">
|
||||
Aspect_Ratio
|
||||
</span>
|
||||
<span class="btn-tooltip" th:text="#{sign.maintainRatio}"></span>
|
||||
</button>
|
||||
<button class="btn btn-outline-secondary" onclick="goToFirstOrLastPage(false)" style="margin-left:auto">
|
||||
<button class="btn btn-outline-secondary" th:title="#{sign.first}" onclick="goToFirstOrLastPage(false)"
|
||||
style="margin-left:auto">
|
||||
<span class="material-symbols-rounded">
|
||||
keyboard_double_arrow_left
|
||||
</span>
|
||||
<span class="btn-tooltip" th:text="#{sign.first}"></span>
|
||||
</button>
|
||||
<button class="btn btn-outline-secondary" id="incrementPage"
|
||||
<button class="btn btn-outline-secondary" th:title="#{sign.previous}" id="incrementPage"
|
||||
onclick="document.documentElement.getAttribute('dir')==='rtl' ? DraggableUtils.incrementPage() : DraggableUtils.decrementPage()">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor"
|
||||
class="bi bi-chevron-left" viewBox="0 0 16 16">
|
||||
<path fill-rule="evenodd"
|
||||
d="M11.354 1.646a.5.5 0 0 1 0 .708L5.707 8l5.647 5.646a.5.5 0 0 1-.708.708l-6-6a.5.5 0 0 1 0-.708l6-6a.5.5 0 0 1 .708 0z" />
|
||||
</svg>
|
||||
<span class="btn-tooltip" th:text="#{sign.previous}"></span>
|
||||
</button>
|
||||
<button class="btn btn-outline-secondary" id="decrementPage"
|
||||
<button class="btn btn-outline-secondary" th:title="#{sign.next}" id="decrementPage"
|
||||
onclick="document.documentElement.getAttribute('dir')==='rtl' ? DraggableUtils.decrementPage() : DraggableUtils.incrementPage()">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor"
|
||||
class="bi bi-chevron-right" viewBox="0 0 16 16">
|
||||
<path fill-rule="evenodd"
|
||||
d="M4.646 1.646a.5.5 0 0 1 .708 0l6 6a.5.5 0 0 1 0 .708l-6 6a.5.5 0 0 1-.708-.708L10.293 8 4.646 2.354a.5.5 0 0 1 0-.708z" />
|
||||
</svg>
|
||||
<span class="btn-tooltip" th:text="#{sign.next}"></span>
|
||||
</button>
|
||||
<button class="btn btn-outline-secondary" onclick="goToFirstOrLastPage(true)">
|
||||
<button class="btn btn-outline-secondary" th:title="#{sign.last}" onclick="goToFirstOrLastPage(true)">
|
||||
<span class="material-symbols-rounded">
|
||||
keyboard_double_arrow_right
|
||||
</span>
|
||||
<span class="btn-tooltip" th:text="#{sign.last}"></span>
|
||||
</button>
|
||||
<button id="download-pdf" class="btn btn-outline-secondary"
|
||||
<button id="download-pdf" th:title="#{downloadPdf}" class="btn btn-outline-secondary"
|
||||
style="border-color: green; color:#b2e3a8; background: rgba(24, 122, 5, 1)">
|
||||
<span class="material-symbols-rounded">
|
||||
download
|
||||
</span>
|
||||
<span class="btn-tooltip" th:text="#{downloadPdf}"></span>
|
||||
</button>
|
||||
</div>
|
||||
<!-- draggables box -->
|
||||
|
@ -3,7 +3,6 @@
|
||||
<head>
|
||||
<th:block th:insert="~{fragments/common :: head(title=#{auto-rename.title}, header=#{auto-rename.header})}"></th:block>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<th:block th:insert="~{fragments/common :: game}"></th:block>
|
||||
<div id="page-container">
|
||||
@ -14,7 +13,11 @@
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-md-6 bg-card">
|
||||
<div class="tool-header">
|
||||
<span class="material-symbols-rounded tool-header-icon advance">text_fields_alt</span>
|
||||
<span >
|
||||
<svg class="tool-header-icon advance">
|
||||
<use xlink:href="/images/rename.svg#icon-rename"></use>
|
||||
</svg>
|
||||
</span>
|
||||
<span class="tool-header-text" th:text="#{auto-rename.header}"></span>
|
||||
</div>
|
||||
<form method="post" enctype="multipart/form-data" th:action="@{'/api/v1/misc/auto-rename'}">
|
||||
|
@ -27,96 +27,84 @@
|
||||
th:placeholder="#{multiTool.uploadPrompts}">
|
||||
</div>
|
||||
<div class="mt-action-btn">
|
||||
<button class="btn btn-primary" onclick="addFiles()">
|
||||
<button class="btn btn-primary" th:title="#{multiTool.addFile}" onclick="addFiles()">
|
||||
<span class="material-symbols-rounded">
|
||||
add
|
||||
</span>
|
||||
<span class="btn-tooltip" th:text="#{multiTool.addFile}"></span>
|
||||
</button>
|
||||
<button class="btn btn-secondary enable-on-file" onclick="rotateAll(-90)" disabled>
|
||||
<button class="btn btn-secondary enable-on-file" th:title="#{multiTool.rotateLeft}"
|
||||
onclick="rotateAll(-90)" disabled>
|
||||
<span class="material-symbols-rounded">
|
||||
rotate_left
|
||||
</span>
|
||||
<span class="btn-tooltip" th:text="#{multiTool.rotateLeft}"></span>
|
||||
</button>
|
||||
<button class="btn btn-secondary enable-on-file" onclick="rotateAll(90)" disabled>
|
||||
<button class="btn btn-secondary enable-on-file" th:title="#{multiTool.rotateRight}"
|
||||
onclick="rotateAll(90)" disabled>
|
||||
<span class="material-symbols-rounded">
|
||||
rotate_right
|
||||
</span>
|
||||
<span class="btn-tooltip" th:text="#{multiTool.rotateRight}"></span>
|
||||
</button>
|
||||
<button class="btn btn-secondary enable-on-file" onclick="splitAll()" disabled>
|
||||
<button class="btn btn-secondary enable-on-file" th:title="#{multiTool.split}" onclick="splitAll()"
|
||||
disabled>
|
||||
<span class="material-symbols-rounded">
|
||||
cut
|
||||
</span>
|
||||
<span class="btn-tooltip" th:text="#{multiTool.split}"></span>
|
||||
</button>
|
||||
<button class="btn btn-secondary enable-on-file" onclick="addFilesBlankAll()" disabled>
|
||||
<button class="btn btn-secondary enable-on-file" th:title="#{multiTool.insertPageBreak}"
|
||||
onclick="addFilesBlankAll()" disabled>
|
||||
<span class="material-symbols-rounded">
|
||||
insert_page_break
|
||||
</span>
|
||||
<span class="btn-tooltip" th:text="#{multiTool.insertPageBreak}"></span>
|
||||
</button>
|
||||
<button id="undo-btn" class="btn btn-secondary" onclick="undo()" disabled>
|
||||
<button id="undo-btn" th:title="#{multiTool.undo}" class="btn btn-secondary" onclick="undo()"
|
||||
disabled>
|
||||
<span class="material-symbols-rounded">
|
||||
undo
|
||||
</span>
|
||||
<span class="btn-tooltip">
|
||||
<div th:text="#{multiTool.undo}"></div>
|
||||
<div class="text-uppercase" th:text="'(CTRL + Z)'"></div>
|
||||
</span>
|
||||
</button>
|
||||
|
||||
<button id="redo-btn" class="btn btn-secondary" onclick="redo()" disabled>
|
||||
<button id="redo-btn" class="btn btn-secondary" th:title="#{multiTool.redo}" onclick="redo()"
|
||||
disabled>
|
||||
<span class="material-symbols-rounded">
|
||||
redo
|
||||
</span>
|
||||
<span class="btn-tooltip">
|
||||
<div th:text="#{multiTool.redo}"></div>
|
||||
<div class="text-uppercase" th:text="'(CTRL + Y)'"></div>
|
||||
</span>
|
||||
</button>
|
||||
</button>
|
||||
|
||||
<button id="select-pages-container" class="btn btn-secondary enable-on-file"
|
||||
onclick="toggleSelectPageVisibility()" disabled>
|
||||
<button id="select-pages-container" th:title="#{multiTool.selectPages}"
|
||||
class="btn btn-secondary enable-on-file" onclick="toggleSelectPageVisibility()" disabled>
|
||||
<span id="select-pages-button" class="material-symbols-rounded">
|
||||
event_list
|
||||
</span>
|
||||
<span class="btn-tooltip" th:text="#{multiTool.selectPages}"></span>
|
||||
|
||||
</button>
|
||||
<button id="deselect-All-Container" class="btn btn-secondary enable-on-file hidden"
|
||||
onclick="toggleSelectAll()" disabled>
|
||||
<button id="deselect-All-Container" th:title="#{multiTool.deselectAll}"
|
||||
class="btn btn-secondary enable-on-file hidden" onclick="toggleSelectAll()" disabled>
|
||||
<span class="material-symbols-rounded" id="deselect-icon">deselect</span>
|
||||
<span class="btn-tooltip" th:text="#{multiTool.deselectAll}"></span>
|
||||
</button>
|
||||
<button id="select-All-Container" class="btn btn-secondary enable-on-file hidden"
|
||||
onclick="toggleSelectAll()" disabled>
|
||||
<button id="select-All-Container" th:title="#{multiTool.selectAll}"
|
||||
class="btn btn-secondary enable-on-file hidden" onclick="toggleSelectAll()" disabled>
|
||||
<span class="material-symbols-rounded" id="select-icon">select_all</span>
|
||||
<span class="btn-tooltip" th:text="#{multiTool.selectAll}"></span>
|
||||
</button>
|
||||
<div class="button-container">
|
||||
<button id="delete-button" class="btn btn-danger delete hidden" onclick="deleteSelected()">
|
||||
<button id="delete-button" th:title="#{multiTool.deleteSelected}"
|
||||
class="btn btn-danger delete hidden" onclick="deleteSelected()">
|
||||
<span class="material-symbols-rounded">delete</span>
|
||||
<span class="btn-tooltip" th:text="#{multiTool.deleteSelected}"></span>
|
||||
</button>
|
||||
</div>
|
||||
<div style="margin-left:auto">
|
||||
<button id="export-selected-button"
|
||||
<button id="export-selected-button" th:title="#{multiTool.downloadSelected}"
|
||||
style="border-color: green; color:#b2e3a8; background: rgba(24, 122, 5, 1)"
|
||||
class="btn btn-primary enable-on-file hidden" onclick="exportPdf(true)" disabled>
|
||||
<span class="btn-tooltip" th:text="#{multiTool.downloadSelected}"></span>
|
||||
<span class="material-symbols-rounded">
|
||||
file_save
|
||||
</span>
|
||||
</button>
|
||||
<button style="border-color: green; color:#b2e3a8; background: rgba(24, 122, 5, 1)"
|
||||
id="export-button" class="btn btn-primary enable-on-file" onclick="exportPdf(false)" disabled>
|
||||
th:title="#{multiTool.downloadAll}" id="export-button" class="btn btn-primary enable-on-file"
|
||||
onclick="exportPdf(false)" disabled>
|
||||
<span class="material-symbols-rounded">
|
||||
download
|
||||
</span>
|
||||
<span class="btn-tooltip" th:text="#{multiTool.downloadAll}"></span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -13,7 +13,7 @@
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-md-6 bg-card">
|
||||
<div class="tool-header">
|
||||
<span class="material-symbols-rounded tool-header-icon security">ink_eraser</span>
|
||||
<span class="material-symbols-rounded tool-header-icon security">playlist_remove</span>
|
||||
<span class="tool-header-text" th:text="#{autoRedact.header}"></span>
|
||||
</div>
|
||||
<form th:action="@{'api/v1/security/auto-redact'}" method="post" enctype="multipart/form-data">
|
||||
|
@ -31,7 +31,7 @@
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-md-6 bg-card">
|
||||
<div class="tool-header">
|
||||
<span class="material-symbols-rounded tool-header-icon security">ink_eraser</span>
|
||||
<span class="material-symbols-rounded tool-header-icon security">playlist_remove</span>
|
||||
<span class="tool-header-text" th:text="#{redact.header}"></span>
|
||||
</div>
|
||||
<form th:action="@{'api/v1/security/redact'}" method="post" enctype="multipart/form-data">
|
||||
@ -56,7 +56,7 @@
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="pageBasedRedactionOverlay" class="d-none col-md-4 row justify-content-center align-content-center">
|
||||
<div class="bg-card">
|
||||
@ -86,25 +86,19 @@
|
||||
<div id="toolbarSidebar">
|
||||
<div id="toolbarSidebarLeft">
|
||||
<div id="sidebarViewButtons" class="splitToolbarButton toggled" role="radiogroup">
|
||||
<button id="viewThumbnail" class="toolbarButton toggled toolbar-btn-hover" tabindex="2"
|
||||
<button id="viewThumbnail" th:title="#{redact.showThumbnails}" class="toolbarButton toggled" tabindex="2"
|
||||
data-l10n-id="pdfjs-thumbs-button" role="radio" aria-checked="true" aria-controls="thumbnailView">
|
||||
<span class="btn-tooltip" th:text="#{redact.showThumbnails}"></span>
|
||||
</button>
|
||||
<button id="viewOutline" class="toolbarButton toolbar-btn-hover"
|
||||
tabindex="3"
|
||||
<button id="viewOutline" th:title="#{redact.showDocumentOutline}" class="toolbarButton" tabindex="3"
|
||||
data-l10n-id="pdfjs-document-outline-button" role="radio" aria-checked="false"
|
||||
aria-controls="outlineView">
|
||||
<span class="btn-tooltip" th:text="#{redact.showDocumentOutline}"></span>
|
||||
</button>
|
||||
<button id="viewAttachments" class="d-none toolbarButton" tabindex="4"
|
||||
<button id="viewAttachments" th:title="#{redact.showAttachments}" class="d-none toolbarButton" tabindex="4"
|
||||
data-l10n-id="pdfjs-attachments-button" role="radio" aria-checked="false" aria-controls="attachmentsView">
|
||||
<span class="btn-tooltip" th:text="#{redact.showAttachments}"></span>
|
||||
<span data-l10n-id="pdfjs-attachments-button-label">Attachments</span>
|
||||
</button>
|
||||
<button id="viewLayers" class="d-none toolbarButton"
|
||||
tabindex="5"
|
||||
<button id="viewLayers" th:title="#{redact.showLayers}" class="d-none toolbarButton" tabindex="5"
|
||||
data-l10n-id="pdfjs-layers-button" role="radio" aria-checked="false" aria-controls="layersView">
|
||||
<span class="btn-tooltip" th:text="#{redact.showLayers}"></span>
|
||||
<span data-l10n-id="pdfjs-layers-button-label">Layers</span>
|
||||
</button>
|
||||
</div>
|
||||
@ -114,9 +108,8 @@
|
||||
<div id="outlineOptionsContainer">
|
||||
<div class="verticalToolbarSeparator"></div>
|
||||
|
||||
<button id="currentOutlineItem" class="toolbarButton" disabled="disabled"
|
||||
tabindex="6" data-l10n-id="pdfjs-current-outline-item-button">
|
||||
<span class="btn-tooltip" th:text="#{redact.findCurrentOutlineItem}"></span>
|
||||
<button id="currentOutlineItem" th:title="#{redact.findCurrentOutlineItem}" class="toolbarButton"
|
||||
disabled="disabled" tabindex="6" data-l10n-id="pdfjs-current-outline-item-button">
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@ -375,8 +368,8 @@
|
||||
</button>
|
||||
</div>
|
||||
<button id="sidebarToggle" class="toolbarButton mt-2" tabindex="11"
|
||||
data-l10n-id="pdfjs-toggle-sidebar-button" aria-expanded="false" aria-controls="sidebarContainer">
|
||||
<span class="btn-tooltip" th:text="#{redact.toggleSidebar}"></span>
|
||||
data-l10n-id="pdfjs-toggle-sidebar-button" th:title="#{redact.toggleSidebar}" aria-expanded="false"
|
||||
aria-controls="sidebarContainer">
|
||||
</button>
|
||||
<div class="toolbarButtonSpacer d-none"></div>
|
||||
<button id="viewFind" class="d-none toolbarButton" title="Find in Document" tabindex="12"
|
||||
@ -384,14 +377,12 @@
|
||||
<span data-l10n-id="pdfjs-findbar-button-label">Find</span>
|
||||
</button>
|
||||
<div class="splitToolbarButton hiddenSmallView">
|
||||
<button class="toolbarButton btn-secondary toolbar-btn-hover" id="previous" tabindex="13"
|
||||
data-l10n-id="pdfjs-previous-button">
|
||||
<span class="btn-tooltip" th:text="#{redact.previousPage}"></span>
|
||||
<button class="toolbarButton btn-secondary" th:title="#{redact.previousPage}" id="previous"
|
||||
tabindex="13" data-l10n-id="pdfjs-previous-button">
|
||||
</button>
|
||||
<div class="splitToolbarButtonSeparator d-none"></div>
|
||||
<button class="toolbarButton btn-secondary toolbar-btn-hover" id="next" tabindex="14"
|
||||
<button class="toolbarButton btn-secondary" th:title="#{redact.nextPage}" id="next" tabindex="14"
|
||||
data-l10n-id="pdfjs-next-button">
|
||||
<span class="btn-tooltip" th:text="#{redact.nextPage}"></span>
|
||||
</button>
|
||||
</div>
|
||||
<span class="loadingInput start">
|
||||
@ -400,100 +391,91 @@
|
||||
</span>
|
||||
<span id="numPages" class="toolbarLabel"></span>
|
||||
<img class="main-icon user-select-none" th:src="@{'/favicon.svg'}" alt="icon">
|
||||
</div>
|
||||
<div id="toolbarViewerMiddle">
|
||||
<div class="splitToolbarButton">
|
||||
<button id="zoomOut" th:title="#{redact.zoomOut}" class="toolbarButton btn-primary" tabindex="21"
|
||||
data-l10n-id="pdfjs-zoom-out-button">
|
||||
</button>
|
||||
<div class="splitToolbarButtonSeparator"></div>
|
||||
<button id="zoomIn" th:title="#{redact.zoomIn}" class="toolbarButton btn-primary" tabindex="22"
|
||||
data-l10n-id="pdfjs-zoom-in-button">
|
||||
</button>
|
||||
</div>
|
||||
<div id="toolbarViewerMiddle">
|
||||
<div class="splitToolbarButton">
|
||||
<button id="zoomOut" class="toolbarButton btn-primary toolbar-btn-hover" tabindex="21"
|
||||
data-l10n-id="pdfjs-zoom-out-button">
|
||||
<span class="btn-tooltip" th:text="#{redact.zoomOut}"></span>
|
||||
</button>
|
||||
<div class="splitToolbarButtonSeparator"></div>
|
||||
<button id="zoomIn" class="toolbarButton btn-primary toolbar-btn-hover" tabindex="22"
|
||||
data-l10n-id="pdfjs-zoom-in-button">
|
||||
<span class="btn-tooltip" th:text="#{redact.zoomIn}"></span>
|
||||
</button>
|
||||
</div>
|
||||
<span id="scaleSelectContainer" class="dropdownToolbarButton">
|
||||
<select id="scaleSelect" tabindex="23" data-l10n-id="pdfjs-zoom-select">
|
||||
<option id="pageAutoOption" value="auto" selected="selected" data-l10n-id="pdfjs-page-scale-auto">
|
||||
Automatic Zoom</option>
|
||||
<option id="pageActualOption" value="page-actual" data-l10n-id="pdfjs-page-scale-actual">
|
||||
Actual Size</option>
|
||||
<option id="pageFitOption" value="page-fit" data-l10n-id="pdfjs-page-scale-fit">Page
|
||||
Fit
|
||||
</option>
|
||||
<option id="pageWidthOption" value="page-width" data-l10n-id="pdfjs-page-scale-width">
|
||||
Page Width</option>
|
||||
<option id="customScaleOption" value="custom" disabled="disabled" hidden="true"
|
||||
data-l10n-id="pdfjs-page-scale-percent" data-l10n-args='{ "scale": 0 }'>0%</option>
|
||||
<option value="0.5" data-l10n-id="pdfjs-page-scale-percent" data-l10n-args='{ "scale": 50 }'>
|
||||
50%</option>
|
||||
<option value="0.75" data-l10n-id="pdfjs-page-scale-percent" data-l10n-args='{ "scale": 75 }'>75%
|
||||
</option>
|
||||
<option value="1" data-l10n-id="pdfjs-page-scale-percent" data-l10n-args='{ "scale": 100 }'>
|
||||
100%</option>
|
||||
<option value="1.25" data-l10n-id="pdfjs-page-scale-percent" data-l10n-args='{ "scale": 125 }'>125%
|
||||
</option>
|
||||
<option value="1.5" data-l10n-id="pdfjs-page-scale-percent" data-l10n-args='{ "scale": 150 }'>150%
|
||||
</option>
|
||||
<option value="2" data-l10n-id="pdfjs-page-scale-percent" data-l10n-args='{ "scale": 200 }'>
|
||||
200%</option>
|
||||
<option value="3" data-l10n-id="pdfjs-page-scale-percent" data-l10n-args='{ "scale": 300 }'>
|
||||
300%</option>
|
||||
<option value="4" data-l10n-id="pdfjs-page-scale-percent" data-l10n-args='{ "scale": 400 }'>
|
||||
400%</option>
|
||||
</select>
|
||||
<span id="scaleSelectContainer" class="dropdownToolbarButton">
|
||||
<select id="scaleSelect" tabindex="23" data-l10n-id="pdfjs-zoom-select">
|
||||
<option id="pageAutoOption" value="auto" selected="selected" data-l10n-id="pdfjs-page-scale-auto">
|
||||
Automatic Zoom</option>
|
||||
<option id="pageActualOption" value="page-actual" data-l10n-id="pdfjs-page-scale-actual">
|
||||
Actual Size</option>
|
||||
<option id="pageFitOption" value="page-fit" data-l10n-id="pdfjs-page-scale-fit">Page
|
||||
Fit
|
||||
</option>
|
||||
<option id="pageWidthOption" value="page-width" data-l10n-id="pdfjs-page-scale-width">
|
||||
Page Width</option>
|
||||
<option id="customScaleOption" value="custom" disabled="disabled" hidden="true"
|
||||
data-l10n-id="pdfjs-page-scale-percent" data-l10n-args='{ "scale": 0 }'>0%</option>
|
||||
<option value="0.5" data-l10n-id="pdfjs-page-scale-percent" data-l10n-args='{ "scale": 50 }'>
|
||||
50%</option>
|
||||
<option value="0.75" data-l10n-id="pdfjs-page-scale-percent" data-l10n-args='{ "scale": 75 }'>75%
|
||||
</option>
|
||||
<option value="1" data-l10n-id="pdfjs-page-scale-percent" data-l10n-args='{ "scale": 100 }'>
|
||||
100%</option>
|
||||
<option value="1.25" data-l10n-id="pdfjs-page-scale-percent" data-l10n-args='{ "scale": 125 }'>125%
|
||||
</option>
|
||||
<option value="1.5" data-l10n-id="pdfjs-page-scale-percent" data-l10n-args='{ "scale": 150 }'>150%
|
||||
</option>
|
||||
<option value="2" data-l10n-id="pdfjs-page-scale-percent" data-l10n-args='{ "scale": 200 }'>
|
||||
200%</option>
|
||||
<option value="3" data-l10n-id="pdfjs-page-scale-percent" data-l10n-args='{ "scale": 300 }'>
|
||||
300%</option>
|
||||
<option value="4" data-l10n-id="pdfjs-page-scale-percent" data-l10n-args='{ "scale": 400 }'>
|
||||
400%</option>
|
||||
</select>
|
||||
</span>
|
||||
</div>
|
||||
<div id="redactionsToolbarViewer" class="splitToolbarButton d-flex">
|
||||
<button id="man-text-select-redact" th:title="#{redact.textBasedRedaction}" class="btn-primary"
|
||||
tabindex="22">
|
||||
<span id="text-selection" class="material-symbols-rounded user-select-none pe-none">text_select_start
|
||||
</span>
|
||||
</div>
|
||||
<div id="redactionsToolbarViewer" class="splitToolbarButton d-flex">
|
||||
<button id="man-text-select-redact" class="btn-primary" tabindex="22">
|
||||
<span class="btn-tooltip" th:text="#{redact.textBasedRedaction}"></span>
|
||||
<span id="text-selection" class="material-symbols-rounded user-select-none pe-none">text_select_start
|
||||
</span>
|
||||
</button>
|
||||
<button id="man-shape-redact" class="btn-primary" tabindex="22">
|
||||
<span class="btn-tooltip" th:text="#{redact.boxRedaction}"></span>
|
||||
<span id="shape-selection" class="material-symbols-rounded user-select-none pe-none">pageless
|
||||
</span>
|
||||
</button>
|
||||
<button id="redactionsPaletteContainer" class="btn-primary">
|
||||
<span class="btn-tooltip" th:text="#{redact.colourPicker}"></span>
|
||||
<label id="redactions-palette" class="material-symbols-rounded palette-color text-center"
|
||||
style="--palette-color: #000000;">
|
||||
palette
|
||||
<input type="color" name="color-picker">
|
||||
</label>
|
||||
</button>
|
||||
<button id="apply-redaction" class="btn-success d-none" disabled>
|
||||
<span class="btn-tooltip" th:text="#{redact.applyChanges}"></span>
|
||||
<span id="apply-redaction-icon" class="material-symbols-rounded">
|
||||
check
|
||||
</span>
|
||||
</button>
|
||||
</button>
|
||||
<button id="man-shape-redact" th:title="#{redact.boxRedaction}" class="btn-primary" tabindex="22">
|
||||
<span id="shape-selection" class="material-symbols-rounded user-select-none pe-none">pageless
|
||||
</span>
|
||||
</button>
|
||||
<button id="redactionsPaletteContainer" th:title="#{redact.colourPicker}" class="btn-primary">
|
||||
<label id="redactions-palette" class="material-symbols-rounded palette-color text-center"
|
||||
style="--palette-color: #000000;">
|
||||
palette
|
||||
<input type="color" name="color-picker">
|
||||
</label>
|
||||
</button>
|
||||
<button id="apply-redaction" th:title="#{redact.applyChanges}" class="btn-success d-none" disabled>
|
||||
<span id="apply-redaction-icon" class="material-symbols-rounded">
|
||||
check
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
<div id="toolbarViewerRight">
|
||||
<div class="splitToolbarButton">
|
||||
<button id="pdfToImageBtn" class="btn-success">
|
||||
<span class="btn-tooltip" th:text="#{redact.convertPDFToImageLabel}"></span>
|
||||
<span id="pdfToImageBtnIcon" class="material-symbols-rounded">
|
||||
<span id="pdfToImageBtnIcon" th:title="#{redact.convertPDFToImageLabel}"
|
||||
class="material-symbols-rounded">
|
||||
image
|
||||
</span>
|
||||
</button>
|
||||
<button id="pageBasedRedactionBtn" class="btn-primary">
|
||||
<span class="btn-tooltip" th:text="#{redact.pageBasedRedaction}"></span>
|
||||
<span id="pageBasedRedactionBtnIcon" class="material-symbols-rounded">
|
||||
<span id="pageBasedRedactionBtnIcon" th:title="#{redact.pageBasedRedaction}"
|
||||
class="material-symbols-rounded">
|
||||
document_scanner
|
||||
</span>
|
||||
</button>
|
||||
<button id="uploadBtn" class="btn-primary">
|
||||
<span class="btn-tooltip" th:text="#{redact.upload}"></span>
|
||||
<span id="uploadBtnIcon" class="material-symbols-rounded">
|
||||
upload
|
||||
</span>
|
||||
<span id="uploadBtnIcon" class="material-symbols-rounded" th:title="#{redact.upload}"> upload </span>
|
||||
</button>
|
||||
<button id="downloadBtn" class="btn-primary">
|
||||
<span class="btn-tooltip" th:text="#{redact.export}"></span>
|
||||
<span id="downloadBtnIcon" class="material-symbols-rounded">
|
||||
<button id="downloadBtn" class="btn-primary">
|
||||
<span id="downloadBtnIcon" th:title="#{redact.export}" class="material-symbols-rounded">
|
||||
download
|
||||
</span>
|
||||
</button>
|
||||
@ -554,6 +536,7 @@
|
||||
|
||||
<div id="viewerContainer" tabindex="0">
|
||||
<div id="viewer" class="pdfViewer"></div>
|
||||
<th:block th:insert="~{fragments/footer.html :: footer}"></th:block>
|
||||
</div>
|
||||
</div> <!-- mainContainer -->
|
||||
|
||||
|
@ -149,7 +149,7 @@
|
||||
<script th:src="@{'/js/sign/signature-canvas.js'}"></script>
|
||||
<!-- draggables box -->
|
||||
<div class="draggable-buttons-box ignore-rtl">
|
||||
<button class="btn btn-outline-secondary"
|
||||
<button class="btn btn-outline-secondary" th:title="#{sign.delete}"
|
||||
onclick="DraggableUtils.deleteDraggableCanvas(DraggableUtils.getLastInteracted())"
|
||||
style="border-color: #C02223; color: #C02223; background: rgba(255, 0, 0, 0.1)">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-trash"
|
||||
@ -159,14 +159,12 @@
|
||||
<path
|
||||
d="M14.5 3a1 1 0 0 1-1 1H13v9a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V4h-.5a1 1 0 0 1-1-1V2a1 1 0 0 1 1-1H6a1 1 0 0 1 1-1h2a1 1 0 0 1 1 1h3.5a1 1 0 0 1 1 1v1ZM4.118 4 4 4.059V13a1 1 0 0 0 1 1h6a1 1 0 0 0 1-1V4.059L11.882 4H4.118ZM2.5 3h11V2h-11v1Z" />
|
||||
</svg>
|
||||
<span class="btn-tooltip" th:text="#{sign.delete}"></span>
|
||||
</button>
|
||||
<button class="btn btn-outline-secondary"
|
||||
<button class="btn btn-outline-secondary" th:title="#{sign.addToAll}"
|
||||
onclick="DraggableUtils.addAllPagesDraggableCanvas(DraggableUtils.getLastInteracted())">
|
||||
<span class="material-symbols-rounded">
|
||||
content_copy
|
||||
</span>
|
||||
<span class="btn-tooltip" th:text="#{sign.addToAll}"></span>
|
||||
</button>
|
||||
<div id="rotation-controls" class="align-items-center" style="display: none;">
|
||||
<div class="input-with-icon">
|
||||
@ -177,49 +175,44 @@
|
||||
style="width: 6rem" />
|
||||
</div>
|
||||
</div>
|
||||
<button id="ratioToggleBtn" class="btn btn-outline-secondary"
|
||||
<button id="ratioToggleBtn" th:title="#{sign.maintainRatio}" class="btn btn-outline-secondary"
|
||||
onclick="DraggableUtils.toggleMaintainRatio()">
|
||||
<span class="material-symbols-rounded">
|
||||
Aspect_Ratio
|
||||
</span>
|
||||
<span class="btn-tooltip" th:text="#{sign.maintainRatio}"></span>
|
||||
</button>
|
||||
<button class="btn btn-outline-secondary" onclick="goToFirstOrLastPage(false)" style="margin-left:auto">
|
||||
<button class="btn btn-outline-secondary" th:title="#{sign.first}" onclick="goToFirstOrLastPage(false)"
|
||||
style="margin-left:auto">
|
||||
<span class="material-symbols-rounded">
|
||||
keyboard_double_arrow_left
|
||||
</span>
|
||||
<span class="btn-tooltip" th:text="#{sign.first}"></span>
|
||||
</button>
|
||||
<button class="btn btn-outline-secondary" id="incrementPage"
|
||||
<button class="btn btn-outline-secondary" th:title="#{sign.previous}" id="incrementPage"
|
||||
onclick="document.documentElement.getAttribute('dir')==='rtl' ? DraggableUtils.incrementPage() : DraggableUtils.decrementPage()">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor"
|
||||
class="bi bi-chevron-left" viewBox="0 0 16 16">
|
||||
<path fill-rule="evenodd"
|
||||
d="M11.354 1.646a.5.5 0 0 1 0 .708L5.707 8l5.647 5.646a.5.5 0 0 1-.708.708l-6-6a.5.5 0 0 1 0-.708l6-6a.5.5 0 0 1 .708 0z" />
|
||||
</svg>
|
||||
<span class="btn-tooltip" th:text="#{sign.previous}"></span>
|
||||
</button>
|
||||
<button class="btn btn-outline-secondary" id="decrementPage"
|
||||
<button class="btn btn-outline-secondary" id="decrementPage" th:title="#{sign.next}"
|
||||
onclick="document.documentElement.getAttribute('dir')==='rtl' ? DraggableUtils.decrementPage() : DraggableUtils.incrementPage()">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor"
|
||||
class="bi bi-chevron-right" viewBox="0 0 16 16">
|
||||
<path fill-rule="evenodd"
|
||||
d="M4.646 1.646a.5.5 0 0 1 .708 0l6 6a.5.5 0 0 1 0 .708l-6 6a.5.5 0 0 1-.708-.708L10.293 8 4.646 2.354a.5.5 0 0 1 0-.708z" />
|
||||
</svg>
|
||||
<span class="btn-tooltip" th:text="#{sign.next}"></span>
|
||||
</button>
|
||||
<button class="btn btn-outline-secondary" onclick="goToFirstOrLastPage(true)">
|
||||
<button class="btn btn-outline-secondary" th:title="#{sign.last}" onclick="goToFirstOrLastPage(true)">
|
||||
<span class="material-symbols-rounded">
|
||||
keyboard_double_arrow_right
|
||||
</span>
|
||||
<span class="btn-tooltip" th:text="#{sign.last}"></span>
|
||||
</button>
|
||||
<button id="download-pdf" class="btn btn-outline-secondary"
|
||||
<button id="download-pdf" th:title="#{downloadPdf}" class="btn btn-outline-secondary"
|
||||
style="border-color: green; color:#b2e3a8; background: rgba(24, 122, 5, 1)">
|
||||
<span class="material-symbols-rounded">
|
||||
download
|
||||
</span>
|
||||
<span class="btn-tooltip" th:text="#{downloadPdf}"></span>
|
||||
</button>
|
||||
</div>
|
||||
<div id="box-drag-container" class="show-on-file-selected">
|
||||
|
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user