Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
A
ai-box
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
青山
ai-box
Commits
d9e26e65
Commit
d9e26e65
authored
Apr 01, 2025
by
fisherdaddy
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
feat: add ScrollToTopButton component and styles for improved navigation
parent
d562dab4
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
128 additions
and
0 deletions
+128
-0
AITimeline.jsx
src/components/AITimeline.jsx
+4
-0
ScrollToTopButton.jsx
src/components/ScrollToTopButton.jsx
+26
-0
useScrollToTopButton.js
src/hooks/useScrollToTopButton.js
+39
-0
HorizontalTimeline.css
src/styles/HorizontalTimeline.css
+59
-0
No files found.
src/components/AITimeline.jsx
View file @
d9e26e65
...
@@ -6,6 +6,7 @@ import SEO from './SEO';
...
@@ -6,6 +6,7 @@ import SEO from './SEO';
import
{
useTranslation
}
from
'../js/i18n'
;
import
{
useTranslation
}
from
'../js/i18n'
;
import
{
usePageLoading
}
from
'../hooks/usePageLoading'
;
import
{
usePageLoading
}
from
'../hooks/usePageLoading'
;
import
LoadingOverlay
from
'./LoadingOverlay'
;
import
LoadingOverlay
from
'./LoadingOverlay'
;
import
ScrollToTopButton
from
'./ScrollToTopButton'
;
const
categories
=
[
const
categories
=
[
{
id
:
'all'
,
label
:
'All Events'
},
{
id
:
'all'
,
label
:
'All Events'
},
...
@@ -171,6 +172,9 @@ const AITimeline = () => {
...
@@ -171,6 +172,9 @@ const AITimeline = () => {
);
);
})
}
})
}
</
div
>
</
div
>
{
/* Scroll to top button */
}
<
ScrollToTopButton
/>
</
div
>
</
div
>
</>
</>
);
);
...
...
src/components/ScrollToTopButton.jsx
0 → 100644
View file @
d9e26e65
import
React
from
'react'
;
import
{
useScrollToTopButton
}
from
'../hooks/useScrollToTopButton'
;
import
{
useTranslation
}
from
'../js/i18n'
;
/**
* A button that appears when the user scrolls down, allowing them to quickly
* return to the top of the page with a smooth animation.
*/
const
ScrollToTopButton
=
()
=>
{
const
{
showButton
,
scrollToTop
}
=
useScrollToTopButton
();
const
{
t
}
=
useTranslation
();
return
(
<
button
className=
{
`scroll-top-button ${showButton ? 'visible' : ''}`
}
onClick=
{
scrollToTop
}
aria
-
label=
{
t
(
'common.scrollToTop'
,
'回到顶部'
)
}
>
<
svg
xmlns=
"http://www.w3.org/2000/svg"
viewBox=
"0 0 24 24"
fill=
"none"
stroke=
"currentColor"
strokeWidth=
"2"
strokeLinecap=
"round"
strokeLinejoin=
"round"
>
<
path
d=
"M18 15l-6-6-6 6"
/>
</
svg
>
</
button
>
);
};
export
default
ScrollToTopButton
;
\ No newline at end of file
src/hooks/useScrollToTopButton.js
0 → 100644
View file @
d9e26e65
import
{
useState
,
useEffect
}
from
'react'
;
/**
* Custom hook to manage a scroll-to-top button that appears
* when the user scrolls beyond the viewport height
*/
export
const
useScrollToTopButton
=
()
=>
{
const
[
showButton
,
setShowButton
]
=
useState
(
false
);
useEffect
(()
=>
{
const
handleScroll
=
()
=>
{
// Show button when scrolled beyond one viewport height
const
scrollThreshold
=
window
.
innerHeight
*
0.7
;
setShowButton
(
window
.
scrollY
>
scrollThreshold
);
};
// Add scroll event listener
window
.
addEventListener
(
'scroll'
,
handleScroll
);
// Initial check
handleScroll
();
// Clean up event listener
return
()
=>
{
window
.
removeEventListener
(
'scroll'
,
handleScroll
);
};
},
[]);
const
scrollToTop
=
()
=>
{
window
.
scrollTo
({
top
:
0
,
behavior
:
'smooth'
});
};
return
{
showButton
,
scrollToTop
};
};
export
default
useScrollToTopButton
;
\ No newline at end of file
src/styles/HorizontalTimeline.css
View file @
d9e26e65
...
@@ -349,4 +349,63 @@
...
@@ -349,4 +349,63 @@
.timeline-meta-info
p
{
.timeline-meta-info
p
{
font-size
:
0.75rem
;
font-size
:
0.75rem
;
}
}
}
/* Scroll to top button */
.scroll-top-button
{
position
:
fixed
;
bottom
:
30px
;
right
:
30px
;
width
:
45px
;
height
:
45px
;
border-radius
:
50%
;
background
:
linear-gradient
(
135deg
,
#6366F1
0%
,
#4F46E5
100%
);
color
:
white
;
border
:
none
;
display
:
flex
;
align-items
:
center
;
justify-content
:
center
;
cursor
:
pointer
;
opacity
:
0
;
visibility
:
hidden
;
transition
:
all
0.3s
ease
;
box-shadow
:
0
4px
12px
rgba
(
99
,
102
,
241
,
0.3
);
z-index
:
100
;
transform
:
translateY
(
20px
);
}
.scroll-top-button.visible
{
opacity
:
1
;
visibility
:
visible
;
transform
:
translateY
(
0
);
animation
:
pulse
2s
infinite
;
}
.scroll-top-button
:hover
{
transform
:
translateY
(
-3px
)
scale
(
1.05
);
box-shadow
:
0
8px
15px
rgba
(
99
,
102
,
241
,
0.4
);
animation
:
none
;
background
:
linear-gradient
(
135deg
,
#4F46E5
0%
,
#3730A3
100%
);
}
.scroll-top-button
:active
{
transform
:
translateY
(
-1px
);
box-shadow
:
0
4px
8px
rgba
(
99
,
102
,
241
,
0.3
);
}
.scroll-top-button
svg
{
width
:
20px
;
height
:
20px
;
}
@keyframes
pulse
{
0
%
{
box-shadow
:
0
0
0
0
rgba
(
99
,
102
,
241
,
0.5
);
}
70
%
{
box-shadow
:
0
0
0
10px
rgba
(
99
,
102
,
241
,
0
);
}
100
%
{
box-shadow
:
0
0
0
0
rgba
(
99
,
102
,
241
,
0
);
}
}
}
\ No newline at end of file
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment