mirror of
https://github.com/hugo-fixit/FixIt.git
synced 2026-08-24 15:28:57 +00:00
feat(link): add external link guard feature support (#729)
* feat(external-link-guard): add native redirect mode and improve external-link guard UX * fix(external-link-guard): remove redirect_url and clarify scope/new_tab_policy docs * i18n(external-link-guard): localize guard texts across non-English locales * feat(config)!: migrate `site.Params.externalIcon` to `site.Params.link.external_icon` * refactor: implement regular and card link rendering * feat(link-guard): implement link redirection page with copy and confirm functionality * revert * feat: implement link guard dialog for external links --------- Co-authored-by: Cell <1024@lruihao.cn>
This commit is contained in:
@@ -12,6 +12,10 @@ html {
|
||||
container-type: scroll-state;
|
||||
container-name: scroller;
|
||||
|
||||
&:has(dialog[open]) {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
@include media('reduce-motion') {
|
||||
scroll-behavior: auto;
|
||||
}
|
||||
@@ -41,6 +45,11 @@ button {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
button:disabled {
|
||||
opacity: 0.65;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
summary {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
@import 'box-shadow';
|
||||
@import 'compatibility';
|
||||
@import 'link';
|
||||
@import 'link-guard';
|
||||
@import 'loading';
|
||||
@import 'media';
|
||||
@import 'scrollbar-width';
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
/// Shared styles for link guard content blocks.
|
||||
/// Keep this as the single source of truth for both link page card and guard dialog body.
|
||||
@mixin link-guard-content {
|
||||
padding: 1.5rem;
|
||||
border: 1px solid fixit-var(global-border-color-light);
|
||||
background: light-dark(#fff, #1d2230);
|
||||
box-shadow: 0 1rem 2rem light-dark(rgba(15, 23, 42, 0.18), rgba(0, 0, 0, 0.35));
|
||||
@include border-radius(1rem);
|
||||
|
||||
.title {
|
||||
margin-block: 0 0.75rem;
|
||||
font-size: 1.25rem;
|
||||
}
|
||||
|
||||
.message {
|
||||
font-weight: 600;
|
||||
margin-block: 0 0.75rem;
|
||||
}
|
||||
|
||||
.target-wrapper {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
margin-bottom: 0.875rem;
|
||||
}
|
||||
|
||||
.target {
|
||||
margin: 0;
|
||||
padding: 0.5rem 1rem;
|
||||
flex: 1 1 auto;
|
||||
min-width: 0;
|
||||
background: light-dark(#f8fafc, #171b25);
|
||||
border: 1px solid fixit-var(global-border-color);
|
||||
font-family: fixit-var(code-font-family);
|
||||
font-size: 0.875rem;
|
||||
line-height: 1rem;
|
||||
word-break: break-all;
|
||||
@include border-radius;
|
||||
}
|
||||
|
||||
.copy-btn {
|
||||
box-sizing: content-box;
|
||||
width: 1rem;
|
||||
height: 1rem;
|
||||
flex-shrink: 0;
|
||||
padding: 0.5rem;
|
||||
line-height: 1;
|
||||
background: light-dark(#f8fafc, #171b25);
|
||||
border: 1px solid fixit-var(global-border-color);
|
||||
color: fixit-var(global-font-secondary-color);
|
||||
@include border-radius;
|
||||
@include user-select(none);
|
||||
|
||||
&[data-copied] .fa-clone {
|
||||
--fa: "\f00c";
|
||||
font-weight: 900;
|
||||
color: fixit-var(global-link-hover-color);
|
||||
}
|
||||
}
|
||||
|
||||
.actions {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
gap: 0.5rem;
|
||||
font-size: 0.875rem;
|
||||
}
|
||||
|
||||
.cancel-btn,
|
||||
.confirm-btn {
|
||||
padding: 0.5rem 0.875rem;
|
||||
border: 1px solid fixit-var(global-border-color-light);
|
||||
background: light-dark(#f6f8fa, #2a313c);
|
||||
color: fixit-var(global-font-color);
|
||||
@include border-radius;
|
||||
@include user-select(none);
|
||||
}
|
||||
|
||||
.confirm-btn {
|
||||
color: #fff;
|
||||
background-color: fixit-var(primary);
|
||||
border-color: fixit-var(primary);
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,7 @@
|
||||
@import 'fixed-button';
|
||||
@import 'github-corner';
|
||||
@import 'icon';
|
||||
@import 'link-guard';
|
||||
@import 'mask';
|
||||
@import 'noscript-warning';
|
||||
@import 'post-chat';
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
#link-guard-dialog {
|
||||
width: MIN(600px, calc(100% - 2rem));
|
||||
max-width: 100%;
|
||||
border: none;
|
||||
padding: 0;
|
||||
color: fixit-var(global-font-color);
|
||||
background-color: transparent;
|
||||
opacity: 0;
|
||||
transform: translateY(12px) scale(0.98);
|
||||
transition:
|
||||
display 0.2s allow-discrete,
|
||||
overlay 0.2s allow-discrete,
|
||||
transform 0.2s,
|
||||
opacity 0.2s;
|
||||
|
||||
.guard-content {
|
||||
@include link-guard-content;
|
||||
}
|
||||
|
||||
&::backdrop {
|
||||
background-color: rgba(0, 0, 0, 0.25);
|
||||
backdrop-filter: blur(2px);
|
||||
opacity: 0;
|
||||
transition:
|
||||
display 0.2s allow-discrete,
|
||||
overlay 0.2s allow-discrete,
|
||||
opacity 0.2s;
|
||||
}
|
||||
|
||||
&[open] {
|
||||
opacity: 1;
|
||||
transform: translateY(0) scale(1);
|
||||
}
|
||||
|
||||
&[open]::backdrop {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
@starting-style {
|
||||
&[open],
|
||||
&[open]::backdrop {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
&[open] {
|
||||
transform: translateY(12px) scale(0.98);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@include media('xs') {
|
||||
#link-guard-dialog {
|
||||
width: calc(100% - 2rem);
|
||||
|
||||
.guard-content {
|
||||
padding: 1rem;
|
||||
|
||||
.actions {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
}
|
||||
|
||||
.cancel-btn,
|
||||
.confirm-btn {
|
||||
width: 100%;
|
||||
min-width: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -41,7 +41,8 @@
|
||||
@import '_single';
|
||||
@import '_special';
|
||||
@import '_archive';
|
||||
@import 'home';
|
||||
@import '404';
|
||||
@import 'home';
|
||||
@import 'link';
|
||||
@import 'offline';
|
||||
@import "patch";
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
#content-link {
|
||||
margin: auto 0;
|
||||
|
||||
.card {
|
||||
width: MIN(600px, calc(100% - 2rem));
|
||||
box-sizing: border-box;
|
||||
margin: 0 auto;
|
||||
@include link-guard-content;
|
||||
|
||||
@include media('xs') {
|
||||
margin-inline: 0;
|
||||
padding: 1rem;
|
||||
}
|
||||
}
|
||||
|
||||
body:has(&) {
|
||||
@include set-fixit-var(global-background-color, fixit-var(header-background-color));
|
||||
}
|
||||
}
|
||||
@@ -216,11 +216,6 @@
|
||||
}
|
||||
|
||||
#toc-dialog {
|
||||
transition:
|
||||
display 0.2s allow-discrete,
|
||||
overlay 0.2s allow-discrete,
|
||||
translate 0.2s,
|
||||
opacity 0.2s 0.4s;
|
||||
opacity: 0;
|
||||
translate: 100vw 0;
|
||||
width: MIN(calc(100% - 4rem), 460px);
|
||||
@@ -231,6 +226,11 @@
|
||||
border: none;
|
||||
border-left: 1px solid fixit-var(global-border-color-light);
|
||||
background-color: fixit-var(global-background-color);
|
||||
transition:
|
||||
display 0.2s allow-discrete,
|
||||
overlay 0.2s allow-discrete,
|
||||
translate 0.2s,
|
||||
opacity 0.2s 0.4s;
|
||||
|
||||
.toc {
|
||||
max-width: 100%;
|
||||
@@ -255,11 +255,11 @@
|
||||
&::backdrop {
|
||||
background-color: rgba(0, 0, 0, 0.25);
|
||||
backdrop-filter: blur(2px);
|
||||
opacity: 0;
|
||||
transition:
|
||||
display 0.5s allow-discrete,
|
||||
overlay 0.5s allow-discrete,
|
||||
opacity 0.2s 0.4s;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
&[open],
|
||||
@@ -287,7 +287,3 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
html:has(#toc-dialog[open]) {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user