Skip to content

Commit e115453

Browse files
zzq0826isabellewei
andauthored
Add Tooling deployed On Scroll (#258)
* Add Tooling deployed On Scroll * update styles * migrate info from contracts page to tooling page * add info for open source contributors * Support dark mode * Support dark mode * remove fake data --------- Co-authored-by: isabelle <[email protected]>
1 parent 7766afb commit e115453

25 files changed

+1161
-95
lines changed

README.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,24 @@ npm install && npm run dev
1616
- All articles are markdown and stored in `/src/content/docs/`.
1717
- Navigation is JSON in `/src/config/sidebar.ts`
1818

19+
## Tooling on Scroll
20+
21+
If you'd like to add an entry to our [tooling list](http://docs.scroll.xyz/en/developers/scroll-contracts), create a PR to add a new `mdx` file in the [tooling content folder](src/content/tools), using the following template. You can also refer to other existing entries for reference.
22+
23+
```
24+
---
25+
name: "Safe"
26+
category: ["Identity", "Wallet"]
27+
excerpt: "Safe allows you to create smart wallet on chain."
28+
logo: { src: "https://app.safe.global/images/safe-logo-green.png", alt: "Safe Logo" }
29+
website: "https://app.safe.global"
30+
network: ["Mainnet", "Testnet]
31+
noAdditionalInfo: false
32+
---
33+
34+
Add additional info here about how to access this tool on Scroll (ex. contract addresses, tutorials, API URLs)
35+
```
36+
1937
## Credits
2038

2139
- Special thanks to the Chainlink team whose documentation we forked. Their repo is available [here](https://github.com/smartcontractkit/documentation) and viewable at [https://docs.chain.link/](https://docs.chain.link/).

public/locales/en/translation.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@
8989
"erc1155TokenBridge": "ERC1155 Token Bridge",
9090
"theScrollMessenger": "The Scroll Messenger",
9191
"transactionFeesOnScroll": "Transaction Fees on Scroll",
92+
"toolingDeployedOnScroll": "Tooling deployed On Scroll",
9293
"l2Fee": "L2 Fee",
9394
"l1Fee": "L1 Fee",
9495
"gasOracle": "Gas Oracle",
Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
import { useState, useEffect, useRef } from "preact/hooks"
2+
3+
const agentStyle = {
4+
position: "absolute",
5+
bottom: 0,
6+
left: 0,
7+
height: 0,
8+
overflow: "hidden",
9+
paddingTop: 0,
10+
paddingBottom: 0,
11+
border: "none",
12+
}
13+
14+
const mirrorProps = [
15+
"box-sizing",
16+
"width",
17+
"font-size",
18+
"font-weight",
19+
"font-family",
20+
"font-style",
21+
"letter-spacing",
22+
"text-indent",
23+
"white-space",
24+
"word-break",
25+
"overflow-wrap",
26+
"padding-left",
27+
"padding-right",
28+
]
29+
30+
function prevSibling(node, count) {
31+
while (node && count--) {
32+
node = node.previousElementSibling
33+
}
34+
return node
35+
}
36+
37+
const LinesEllipsis = props => {
38+
const { component: Component = "div", ellipsis, trimRight = true, basedOn, maxLine = 1, text, className, onReflow, ...rest } = props
39+
40+
const [displayedText, setDisplayedText] = useState(text)
41+
const [clamped, setClamped] = useState(false)
42+
43+
const units = useRef([])
44+
const shadowRef = useRef<HTMLElement>()
45+
const targetRef = useRef()
46+
const ellipsisRef = useRef()
47+
48+
useEffect(() => {
49+
const handleSizeChanged = entries => {
50+
if (targetRef.current) {
51+
copyStyleToShadow()
52+
reflow({ basedOn, text, maxLine })
53+
}
54+
}
55+
const resizeObserver = new ResizeObserver(handleSizeChanged)
56+
resizeObserver.observe(targetRef.current)
57+
58+
return () => {
59+
if (targetRef.current) {
60+
resizeObserver && resizeObserver.unobserve(targetRef.current)
61+
}
62+
}
63+
}, [basedOn, text, maxLine])
64+
65+
const copyStyleToShadow = () => {
66+
const targetStyle = window.getComputedStyle(targetRef.current)
67+
mirrorProps.forEach(key => {
68+
shadowRef.current.style[key] = targetStyle[key]
69+
})
70+
}
71+
72+
const reflow = props => {
73+
/* eslint-disable no-control-regex */
74+
const basedOn = props.basedOn || (/^[\x00-\x7F]+$/.test(props.text) ? "words" : "letters")
75+
76+
if (basedOn === "words") {
77+
units.current = props.text.split(/\b|(?=\W)/)
78+
} else if (basedOn === "letters") {
79+
units.current = Array.from(props.text)
80+
} else {
81+
// default
82+
units.current = props.text.split(/\b|(?=\W)/)
83+
}
84+
shadowRef.current.innerHTML = units.current
85+
.map(c => {
86+
return `<span class='LinesEllipsis-unit'>${c}</span>`
87+
})
88+
.join("")
89+
const ellipsisIndex = putEllipsis(calcIndexes())
90+
const nextClamped = ellipsisIndex > -1
91+
const nextDisplayedText = nextClamped ? units.current.slice(0, ellipsisIndex).join("") : props.text
92+
setClamped(nextClamped)
93+
setDisplayedText(nextDisplayedText)
94+
onReflow({ clamped: nextClamped, text: nextDisplayedText })
95+
}
96+
97+
// return the index of the first letter/word of each line
98+
// row count: maxLine + 1
99+
const calcIndexes = () => {
100+
const indexes = [0]
101+
let spanNode = shadowRef.current.firstElementChild
102+
if (!spanNode) return indexes
103+
104+
let index = 0
105+
let line = 1
106+
let offsetTop = spanNode.offsetTop
107+
while ((spanNode = spanNode.nextElementSibling)) {
108+
if (spanNode.offsetTop > offsetTop) {
109+
line++
110+
indexes.push(index)
111+
offsetTop = spanNode.offsetTop
112+
}
113+
index++
114+
if (line > maxLine) {
115+
break
116+
}
117+
}
118+
return indexes
119+
}
120+
121+
const putEllipsis = indexes => {
122+
// no ellipsis
123+
if (indexes.length <= maxLine) return -1
124+
const lastIndex = indexes[maxLine]
125+
const truncatedUnits = units.current.slice(0, lastIndex)
126+
127+
// the first letter/word of maxLine + 1 row
128+
const maxOffsetTop = shadowRef.current.children[lastIndex].offsetTop
129+
shadowRef.current.innerHTML =
130+
truncatedUnits
131+
.map((c, i) => {
132+
return `<span class='LinesEllipsis-unit'>${c}</span>`
133+
})
134+
.join("") + `<span class='LinesEllipsis-ellipsis'>${ellipsisRef.current.innerHTML}</span>`
135+
const ellipsisNode = shadowRef.current.lastElementChild
136+
let lastTextNode = prevSibling(ellipsisNode, 1)
137+
while (
138+
lastTextNode &&
139+
(ellipsisNode.offsetTop > maxOffsetTop ||
140+
ellipsisNode.offsetHeight > lastTextNode.offsetHeight ||
141+
ellipsisNode.offsetTop > lastTextNode.offsetTop)
142+
) {
143+
shadowRef.current.removeChild(lastTextNode)
144+
lastTextNode = prevSibling(ellipsisNode, 1)
145+
truncatedUnits.pop()
146+
}
147+
return truncatedUnits.length
148+
}
149+
150+
return (
151+
<>
152+
<Component className={`LinesEllipsis ${clamped ? "LinesEllipsis--clamped" : ""} ${className}`} ref={targetRef} {...rest}>
153+
{trimRight ? displayedText.trimRight() : displayedText}
154+
{clamped && <span className="LinesEllipsis-ellipsis">{ellipsis}</span>}
155+
</Component>
156+
<div style={agentStyle} ref={shadowRef} className={`LinesEllipsis-shadow ${className}`}></div>
157+
<span style={agentStyle} ref={ellipsisRef}>
158+
{ellipsis}
159+
</span>
160+
</>
161+
)
162+
}
163+
164+
export default LinesEllipsis
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
.additionalInfo {
2+
height: 100%;
3+
overflow: auto;
4+
background: rgba(255, 255, 255, 0.5);
5+
border-radius: 15px;
6+
display: flex;
7+
justify-content: center;
8+
max-width: 532px;
9+
margin: 0 auto;
10+
position: relative;
11+
}
12+
.closeButton {
13+
position: absolute;
14+
right: 20px;
15+
top: 20px;
16+
cursor: pointer;
17+
display: none;
18+
}
19+
.infoBox {
20+
padding: 18px 20px;
21+
width: 100%;
22+
}
23+
24+
.infoBox p {
25+
font-size: 14px;
26+
}
27+
28+
.title {
29+
font-size: 18px;
30+
font-style: normal;
31+
font-weight: 600;
32+
line-height: normal;
33+
letter-spacing: 0.18px;
34+
margin-bottom: 15px;
35+
}
36+
37+
.content {
38+
max-height: 460px;
39+
overflow: auto;
40+
}
41+
42+
.noToolInfo {
43+
text-align: center;
44+
margin: 0 auto;
45+
height: max-content;
46+
max-width: 280px;
47+
align-self: center;
48+
}
49+
50+
.noToolInfo svg {
51+
margin-bottom: 20px;
52+
}
53+
54+
.noToolInfoTitle {
55+
color: #ababab;
56+
text-align: center;
57+
font-size: 18px;
58+
font-style: normal;
59+
font-weight: 600;
60+
line-height: normal;
61+
letter-spacing: 0.18px;
62+
margin-bottom: 8px;
63+
}
64+
65+
.noToolInfoDescription {
66+
color: #ababab;
67+
text-align: center;
68+
font-size: 14px;
69+
font-style: normal;
70+
font-weight: 400;
71+
line-height: 18px; /* 128.571% */
72+
letter-spacing: 0.14px;
73+
}
74+
75+
@media screen and (max-width: 1300px) {
76+
.closeButton {
77+
display: block;
78+
}
79+
.additionalContainer {
80+
position: fixed;
81+
top: 0;
82+
right: 0;
83+
bottom: 0;
84+
left: 0;
85+
background: rgba(16, 16, 16, 0.2);
86+
z-index: 9999;
87+
height: 100%;
88+
max-height: 100%;
89+
padding: 20px;
90+
display: flex;
91+
}
92+
.additionalInfo {
93+
background: #ffffff;
94+
border-radius: 15px;
95+
justify-self: center;
96+
align-self: center;
97+
width: 100%;
98+
height: 532px;
99+
}
100+
101+
.noToolSelected {
102+
display: none;
103+
}
104+
.noToolInfo {
105+
padding-top: 20px;
106+
}
107+
}

0 commit comments

Comments
 (0)