Skip to content

Commit 27b19e5

Browse files
committed
add copy page button
1 parent 6632829 commit 27b19e5

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

45 files changed

+2749
-87
lines changed

jest.config.cjs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ module.exports = {
1313
extensionsToTreatAsEsm: [".ts", ".tsx"],
1414
moduleFileExtensions: ["js", "jsx", "ts", "tsx", "json", "node"],
1515
moduleNameMapper: {
16+
"^(\\.{1,2}/.*)\\.js$": "$1",
1617
"\\.(css)$": "<rootDir>/src/__mocks__/styleMock.ts",
1718
"^~/(.*)$": "<rootDir>/src/$1",
1819
"^@api/(.*)$": "<rootDir>/src/pages/api/$1",
@@ -29,6 +30,7 @@ module.exports = {
2930
"^@variables$": "<rootDir>/src/config/markdown-variables.ts",
3031
"^@abi$": "<rootDir>/src/features/abi/index.ts",
3132
"^@lib$": "<rootDir>/src/lib/index.ts",
33+
"^@lib/(.*)\\.js$": "<rootDir>/src/lib/$1",
3234
"^@lib/(.*)$": "<rootDir>/src/lib/$1",
3335
"\\.ya?ml$": "<rootDir>/src/__mocks__/yamlMock.ts",
3436
},

src/components/Modal/Modal.tsx

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import React from "react"
22
import styles from "./Modal.module.css"
3-
import FocusTrap from "focus-trap-react"
3+
import { FocusTrap } from "focus-trap-react"
44
import { createPortal } from "react-dom"
55
import { useKeyPress } from "~/hooks/useKeyPress.ts"
66
import { clsx } from "~/lib/clsx/clsx.ts"
@@ -24,16 +24,7 @@ export function Modal({
2424
<>
2525
{isOpen &&
2626
createPortal(
27-
// For some reason the error says that the element doesn't match even though it does
28-
// and it also works correctly.
29-
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
30-
// @ts-ignore
3127
<FocusTrap>
32-
{/*
33-
For some reason the error says that the element doesn't match even though it does
34-
and it also works correctly.
35-
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
36-
@ts-ignore */}
3728
<div>
3829
<div className={styles.overlay} onClick={onClose}></div>
3930
<div id={modalId} className={clsx(styles.modal)} tabIndex={0} style={style}>
Lines changed: 219 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,219 @@
1+
/**
2+
* Styles for CopyPageLink component
3+
* Matches MoreMenu styling pattern
4+
*/
5+
6+
.container {
7+
position: relative;
8+
width: 100%;
9+
}
10+
11+
.trigger {
12+
/* Match MoreMenu header-link styling */
13+
display: inline-flex;
14+
align-items: center;
15+
gap: var(--space-2x);
16+
padding: 0.15em 0;
17+
font-size: 14px;
18+
color: var(--blue-600, #375bd2);
19+
background: none;
20+
border: none;
21+
cursor: pointer;
22+
text-decoration: none;
23+
transition: color 0.2s ease;
24+
width: 100%;
25+
text-align: left;
26+
}
27+
28+
.trigger:hover {
29+
color: var(--theme-accent, var(--blue-700));
30+
}
31+
32+
.trigger:focus-visible {
33+
outline: 2px solid var(--blue-600);
34+
outline-offset: 2px;
35+
border-radius: var(--border-radius-primary, 4px);
36+
}
37+
38+
.trigger svg {
39+
flex-shrink: 0;
40+
}
41+
42+
.trigger span {
43+
flex: 1;
44+
}
45+
46+
.dropdown {
47+
position: absolute;
48+
top: calc(100% + var(--space-1x));
49+
left: 0;
50+
min-width: 200px;
51+
background: var(--color-background-primary, #ffffff);
52+
border: 1px solid var(--theme-divider, var(--gray-200));
53+
border-radius: var(--border-radius-primary, 8px);
54+
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
55+
padding: var(--space-1x);
56+
z-index: 1000;
57+
animation: dropdownSlide 0.15s ease-out;
58+
}
59+
60+
@keyframes dropdownSlide {
61+
from {
62+
opacity: 0;
63+
transform: translateY(-4px);
64+
}
65+
to {
66+
opacity: 1;
67+
transform: translateY(0);
68+
}
69+
}
70+
71+
.dropdownItem {
72+
display: flex;
73+
align-items: center;
74+
gap: var(--space-2x);
75+
width: 100%;
76+
padding: var(--space-2x) var(--space-3x);
77+
background: none;
78+
border: none;
79+
border-radius: var(--border-radius-primary, 4px);
80+
font-size: 14px;
81+
color: var(--gray-900, #111827);
82+
cursor: pointer;
83+
text-align: left;
84+
transition: all 0.15s ease;
85+
}
86+
87+
.dropdownItem:hover {
88+
background-color: var(--theme-bg-hover, var(--gray-100));
89+
color: var(--blue-700);
90+
}
91+
92+
.dropdownItem:focus-visible {
93+
outline: 2px solid var(--blue-600);
94+
outline-offset: -2px;
95+
}
96+
97+
.dropdownItem:active {
98+
background-color: var(--gray-200);
99+
}
100+
101+
.dropdownItem svg {
102+
flex-shrink: 0;
103+
opacity: 1;
104+
}
105+
106+
.dropdownItem:hover svg {
107+
opacity: 1;
108+
color: var(--blue-700);
109+
}
110+
111+
/* Separator between action groups */
112+
.dropdownSeparator {
113+
height: 1px;
114+
background-color: var(--gray-300, #d1d5db);
115+
margin: var(--space-2x) 0;
116+
border: none;
117+
}
118+
119+
/* Primary action styling */
120+
.dropdownItemPrimary {
121+
font-weight: 600;
122+
color: #000000;
123+
}
124+
125+
.dropdownItemPrimary svg {
126+
opacity: 1;
127+
}
128+
129+
/* Mobile responsiveness */
130+
@media (max-width: 768px) {
131+
.dropdown {
132+
left: auto;
133+
right: 0;
134+
min-width: 180px;
135+
}
136+
137+
.dropdownItem {
138+
padding: var(--space-3x);
139+
font-size: 15px;
140+
/* Larger tap targets on mobile */
141+
}
142+
}
143+
144+
/* Tablet adjustments */
145+
@media (min-width: 768px) and (max-width: 992px) {
146+
.dropdown {
147+
min-width: 220px;
148+
}
149+
}
150+
151+
/* Dark theme support */
152+
@media (prefers-color-scheme: dark) {
153+
.trigger {
154+
color: var(--blue-400, #5b8dff);
155+
}
156+
157+
.trigger:hover {
158+
color: var(--blue-300, #7aa3ff);
159+
}
160+
161+
.dropdown {
162+
background: var(--color-background-primary, #1a1a1a);
163+
border-color: var(--gray-700);
164+
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
165+
}
166+
167+
.dropdownItem {
168+
color: var(--gray-300);
169+
}
170+
171+
.dropdownItem:hover {
172+
background-color: var(--gray-800);
173+
color: var(--gray-100);
174+
}
175+
176+
.dropdownItem:active {
177+
background-color: var(--gray-700);
178+
}
179+
180+
.dropdownSeparator {
181+
background-color: var(--gray-700);
182+
}
183+
184+
.dropdownItemPrimary {
185+
color: var(--gray-100);
186+
}
187+
}
188+
189+
/* High contrast mode support */
190+
@media (prefers-contrast: high) {
191+
.trigger {
192+
outline: 1px solid currentColor;
193+
padding: 0.25em 0.5em;
194+
}
195+
196+
.dropdown {
197+
border-width: 2px;
198+
}
199+
200+
.dropdownItem {
201+
border: 1px solid transparent;
202+
}
203+
204+
.dropdownItem:hover {
205+
border-color: currentColor;
206+
}
207+
}
208+
209+
/* Reduced motion support */
210+
@media (prefers-reduced-motion: reduce) {
211+
.dropdown {
212+
animation: none;
213+
}
214+
215+
.trigger,
216+
.dropdownItem {
217+
transition: none;
218+
}
219+
}

0 commit comments

Comments
 (0)