Add share button for search results with URL copying

- Implement share button in results page with clipboard functionality
- Add new 'share' SVG icon to icons template
- Create JavaScript event handler for copying search URL
- Update CSS for share button styling in LTR and RTL layouts
- Add tooltip for copied URL feedback
This commit is contained in:
Gnkalk 2025-02-19 20:14:23 +03:30
parent 4798e9bea8
commit 9a3d8629e5
10 changed files with 152 additions and 17 deletions

View file

@ -380,6 +380,10 @@ img, video {
transform: translate(calc(-50% - 1rem), 40%);
}
[tooltip].center-tooltip:before {
transform: translate(-50%, 40%);
}
[tooltip]:hover:after, [tooltip]:hover:before {
opacity: 1;
transition: opacity .25s ease-in-out .5s;
@ -1093,7 +1097,7 @@ main:has(.not-found) .button {
padding: 0 1rem;
transition: grid-template-columns .3s ease-in-out;
display: grid;
overflow: auto;
overflow: hidden auto;
}
@media (width >= 90rem) {
@ -1104,11 +1108,17 @@ main:has(.not-found) .button {
#results .result-count {
color: var(--secondary-text-color);
text-align: end;
grid-area: amount;
font-size: .8rem;
}
#results .result-count-container {
justify-content: end;
align-items: center;
gap: .5rem;
display: flex;
}
#results footer {
grid-area: footer;
}
@ -1193,6 +1203,22 @@ main:has(.not-found) .button {
grid-template-columns: 2fr 0fr 1fr;
}
#results .share_btn {
background-color: #0000;
border: none;
border-radius: 9999px;
padding: .25rem;
}
#results .share_btn:hover {
background-color: var(--background-color);
}
#results .share_btn svg {
width: 1rem;
height: 1rem;
}
.links {
grid-area: links;
justify-content: end;

View file

@ -307,7 +307,7 @@ img, video {
transition: opacity .25s ease-in-out;
position: absolute;
bottom: 100%;
right: 50%;
left: 50%;
transform: translate(-50%, -20%);
}
@ -322,10 +322,14 @@ img, video {
transition: opacity .25s ease-in-out;
position: absolute;
bottom: 100%;
right: 50%;
left: 50%;
transform: translate(calc(-50% - 1rem), 40%);
}
[tooltip].center-tooltip:before {
transform: translate(-50%, 40%);
}
[tooltip]:hover:after, [tooltip]:hover:before {
opacity: 1;
transition: opacity .25s ease-in-out .5s;
@ -869,7 +873,7 @@ fieldset .container .name {
}
fieldset .container .name:not(#pref_safesearch)[tooltip]:after {
right: 100%;
left: 100%;
}
fieldset .container .name svg {
@ -1039,7 +1043,7 @@ main:has(.not-found) .button {
padding: 0 1rem;
transition: grid-template-columns .3s ease-in-out;
display: grid;
overflow: auto;
overflow: hidden auto;
}
@media (width >= 90rem) {
@ -1050,11 +1054,17 @@ main:has(.not-found) .button {
#results .result-count {
color: var(--secondary-text-color);
text-align: end;
grid-area: amount;
font-size: .8rem;
}
#results .result-count-container {
justify-content: end;
align-items: center;
gap: .5rem;
display: flex;
}
#results footer {
grid-area: footer;
}
@ -1139,6 +1149,22 @@ main:has(.not-found) .button {
grid-template-columns: 2fr 0fr 1fr;
}
#results .share_btn {
background-color: #0000;
border: none;
border-radius: 9999px;
padding: .25rem;
}
#results .share_btn:hover {
background-color: var(--background-color);
}
#results .share_btn svg {
width: 1rem;
height: 1rem;
}
.links {
grid-area: links;
justify-content: end;

View file

@ -599,7 +599,7 @@ function $$(selector) {
}
(0, _images.checkImagePage)();
function afterPageLoad() {
// check for preferences page
// preferences page
if ($("#preferences")) {
// check for preferences hash
const hashInput = $("#preferences-hash");
@ -621,6 +621,22 @@ function afterPageLoad() {
pasteInput.value = hash;
});
}
// search page
if ($("#results")) {
const shareBtn = $("#share-url-btn");
if (!shareBtn) return;
shareBtn.addEventListener("click", function() {
const searchUrl = shareBtn.getAttribute("data-search-url");
if (!searchUrl) return;
(0, _utils.copyToClipboard)(searchUrl);
const copiedText = shareBtn.getAttribute("data-gitee-copied");
if (!copiedText) return;
shareBtn.setAttribute("tooltip", copiedText);
setTimeout(()=>{
shareBtn.removeAttribute("tooltip");
}, 2000);
});
}
}
if (document.readyState === "loading") document.addEventListener("DOMContentLoaded", afterPageLoad);
else afterPageLoad();

View file

@ -11,6 +11,7 @@ const svgList = {
plugin: "node_modules/remixicon/icons/Development/puzzle-2-fill.svg",
info: "node_modules/remixicon/icons/System/information-2-fill.svg",
database: "node_modules/remixicon/icons/Device/database-2-fill.svg",
share: "node_modules/remixicon/icons/System/share-fill.svg",
};
const ejs = require("ejs"),

View file

@ -8,7 +8,7 @@
content: attr(tooltip);
position: absolute;
bottom: 100%;
@include mixin.left(50%);
left: 50%;
transform: translate(-50%, -20%);
background: var(--tooltip-background-color);
color: var(--filled-text-color);
@ -24,7 +24,7 @@
content: " ";
position: absolute;
bottom: 100%;
@include mixin.left(50%);
left: 50%;
transform: translate(calc(-50% - 1rem), 40%);
white-space: nowrap;
z-index: 1;
@ -35,6 +35,10 @@
border-color: var(--tooltip-background-color) transparent transparent transparent;
}
*[tooltip].center-tooltip::before {
transform: translate(-50%, 40%);
}
*[tooltip]:hover::after {
opacity: 1;

View file

@ -174,7 +174,7 @@ fieldset {
align-items: center;
&:not(#pref_safesearch)[tooltip]::after {
@include mixin.left(100%);
left: 100%;
}
svg {

View file

@ -197,7 +197,8 @@ main:has(.not-found) {
margin: 0 auto;
padding: 0 1rem;
max-width: 1800px;
overflow: auto;
overflow-x: hidden;
overflow-y: auto;
transition: grid-template-columns 300ms ease-in-out;
@include mixin.screens($screen-xl) {
@ -208,7 +209,13 @@ main:has(.not-found) {
grid-area: amount;
font-size: .8rem;
color: var(--secondary-text-color);
text-align: end;
&-container {
display: flex;
align-items: center;
gap: .5rem;
justify-content: end;
}
}
footer {
@ -296,6 +303,22 @@ main:has(.not-found) {
&.image-open {
grid-template-columns: 2fr 0fr 1fr;
}
.share_btn {
background-color: transparent;
border: none;
@include mixin.rounded(full);
padding: .25rem;
&:hover {
background-color: var(--background-color);
}
svg {
width: 1rem;
height: 1rem;
}
}
}
.links {

View file

@ -12,7 +12,7 @@ export function $$(selector: string) {
checkImagePage();
function afterPageLoad() {
// check for preferences page
// preferences page
if ($("#preferences")) {
// check for preferences hash
const hashInput = $("#preferences-hash") as HTMLInputElement;
@ -40,6 +40,23 @@ function afterPageLoad() {
pasteInput.value = hash;
});
}
// search page
if ($("#results")) {
const shareBtn = $("#share-url-btn") as HTMLButtonElement;
if (!shareBtn) return;
shareBtn.addEventListener("click", function () {
const searchUrl = shareBtn.getAttribute("data-search-url");
if (!searchUrl) return;
copyToClipboard(searchUrl);
const copiedText = shareBtn.getAttribute("data-gitee-copied");
if (!copiedText) return;
shareBtn.setAttribute("tooltip", copiedText);
setTimeout(() => {
shareBtn.removeAttribute("tooltip");
}, 2000);
});
}
}
if (document.readyState === "loading") {

View file

@ -12,6 +12,7 @@
'plugin':'<svg viewBox="0 0 24 24" fill="currentColor" class="icon" aria-hidden="true"><path d="M8 4C8 2.34315 9.34315 1 11 1C12.6569 1 14 2.34315 14 4C14 4.35064 13.9398 4.68722 13.8293 5H20C20.5523 5 21 5.44772 21 6V9.12602C21 9.43517 20.857 9.72694 20.6127 9.91635C20.3683 10.1058 20.0501 10.1715 19.7507 10.0945C19.5119 10.033 19.2605 10 19 10C17.3431 10 16 11.3431 16 13C16 14.6569 17.3431 16 19 16C19.2605 16 19.5119 15.967 19.7507 15.9055C20.0501 15.8285 20.3683 15.8942 20.6127 16.0836C20.857 16.2731 21 16.5648 21 16.874V20C21 20.5523 20.5523 21 20 21H4C3.44772 21 3 20.5523 3 20V6C3 5.44772 3.44772 5 4 5H8.17071C8.06015 4.68722 8 4.35064 8 4Z"/></svg>',
'info':'<svg viewBox="0 0 24 24" fill="currentColor" class="icon" aria-hidden="true"><path d="M12 22C6.47715 22 2 17.5228 2 12C2 6.47715 6.47715 2 12 2C17.5228 2 22 6.47715 22 12C22 17.5228 17.5228 22 12 22ZM12 9.5C12.8284 9.5 13.5 8.82843 13.5 8C13.5 7.17157 12.8284 6.5 12 6.5C11.1716 6.5 10.5 7.17157 10.5 8C10.5 8.82843 11.1716 9.5 12 9.5ZM14 15H13V10.5H10V12.5H11V15H10V17H14V15Z"/></svg>',
'database':'<svg viewBox="0 0 24 24" fill="currentColor" class="icon" aria-hidden="true"><path d="M21 9.5V12.5C21 14.9853 16.9706 17 12 17C7.02944 17 3 14.9853 3 12.5V9.5C3 11.9853 7.02944 14 12 14C16.9706 14 21 11.9853 21 9.5ZM3 14.5C3 16.9853 7.02944 19 12 19C16.9706 19 21 16.9853 21 14.5V17.5C21 19.9853 16.9706 22 12 22C7.02944 22 3 19.9853 3 17.5V14.5ZM12 12C7.02944 12 3 9.98528 3 7.5C3 5.01472 7.02944 3 12 3C16.9706 3 21 5.01472 21 7.5C21 9.98528 16.9706 12 12 12Z"/></svg>',
'share':'<svg viewBox="0 0 24 24" fill="currentColor" class="icon" aria-hidden="true"><path d="M13.5759 17.2714L8.46576 14.484C7.83312 15.112 6.96187 15.5 6 15.5C4.067 15.5 2.5 13.933 2.5 12C2.5 10.067 4.067 8.5 6 8.5C6.96181 8.5 7.83301 8.88796 8.46564 9.51593L13.5759 6.72855C13.5262 6.49354 13.5 6.24983 13.5 6C13.5 4.067 15.067 2.5 17 2.5C18.933 2.5 20.5 4.067 20.5 6C20.5 7.933 18.933 9.5 17 9.5C16.0381 9.5 15.1669 9.11201 14.5343 8.48399L9.42404 11.2713C9.47382 11.5064 9.5 11.7501 9.5 12C9.5 12.2498 9.47383 12.4935 9.42408 12.7285L14.5343 15.516C15.167 14.888 16.0382 14.5 17 14.5C18.933 14.5 20.5 16.067 20.5 18C20.5 19.933 18.933 21.5 17 21.5C15.067 21.5 13.5 19.933 13.5 18C13.5 17.7502 13.5262 17.5064 13.5759 17.2714Z"/></svg>',
}
-%}

View file

@ -58,9 +58,30 @@ block body %} {% include 'smart/madules/search_header.html' %}
{% if infoboxes %} {% include 'smart/madules/infoboxs.html' %} {% endif %}
</div>
{%- if number_of_results != '0' -%}
<p class="result-count">
<small>{{ _('Number of results') }}: {{ number_of_results }}</small>
</p>
<div class="result-count">
<div class="result-count-container">
<small>{{ _('Number of results') }}: {{ number_of_results }}</small>
<button
id="share-url-btn"
class="share_btn center-tooltip"
role="button"
data-search-url="
{{ url_for('search', _external=True) }}?q={{ q|urlencode }}&amp;language={{ current_language }}&amp;time_range={{ time_range }}&amp;safesearch={{ safesearch }}
{%- if pageno > 1 -%}
&amp;pageno={{ pageno }}
{%- endif -%}
{%- if selected_categories -%}
&amp;categories={{ selected_categories|join(',') | replace(' ','+') }}
{%- endif -%}
{%- if timeout_limit -%}
&amp;timeout_limit={{ timeout_limit|urlencode }}
{%- endif -%}"
data-gitee-copied="{{ _('Copied') }}"
>
{{ icon_small('share') }}
</button>
</div>
</div>
{%- endif -%} {% if 'images.html' in
results|map(attribute='template')|unique|list%}
<div class="image-details-container">