Skip to content

Commit 791fa3e

Browse files
committed
Add custom about page and TOS
1 parent 2402564 commit 791fa3e

File tree

6 files changed

+262
-53
lines changed

6 files changed

+262
-53
lines changed

src/App.tsx

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
import { useEffect, useState } from 'react';
2+
import { ThemeProvider } from 'styled-components';
3+
import About from './components/About.tsx';
24
import Editor from './components/Editor';
5+
import usePreference from './hooks/usePreference.ts';
6+
import themes, { Themes } from './style/themes.ts';
37
import { loadFromBytebin } from './util/storage';
48

59
const INITIAL = Symbol();
@@ -14,6 +18,12 @@ export default function App() {
1418
const [forcedContent, setForcedContent] = useState<string>('');
1519
const [actualContent, setActualContent] = useState<string>('');
1620
const [contentType, setContentType] = useState<string>();
21+
const [theme, setTheme] = usePreference<keyof Themes>(
22+
'theme',
23+
'dark',
24+
pref => !!themes[pref]
25+
);
26+
const [showAbout, setShowAbout] = useState<boolean>(true);
1727

1828
function setContent(content: string) {
1929
setActualContent(content);
@@ -40,13 +50,19 @@ export default function App() {
4050
}, [pasteId, state]);
4151

4252
return (
43-
<Editor
44-
forcedContent={forcedContent}
45-
actualContent={actualContent}
46-
setActualContent={setActualContent}
47-
contentType={contentType}
48-
pasteId={pasteId}
49-
/>
53+
<ThemeProvider theme={themes[theme]}>
54+
<Editor
55+
forcedContent={forcedContent}
56+
actualContent={actualContent}
57+
setActualContent={setActualContent}
58+
contentType={contentType}
59+
pasteId={pasteId}
60+
theme={theme}
61+
setTheme={setTheme}
62+
setShowAbout={setShowAbout}
63+
/>
64+
{showAbout && <About setVisible={setShowAbout} />}
65+
</ThemeProvider>
5066
);
5167
}
5268

src/components/About.tsx

Lines changed: 190 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,190 @@
1+
import { useCallback, useState } from 'react';
2+
import styled from 'styled-components';
3+
import Button from './Button.tsx';
4+
5+
const CloseButton = ({
6+
setVisible,
7+
}: {
8+
setVisible: (show: boolean) => void;
9+
}) => {
10+
const close = useCallback(() => {
11+
setVisible(false);
12+
}, [setVisible]);
13+
return (
14+
<div
15+
style={{
16+
position: 'absolute',
17+
top: '5px',
18+
right: '5px',
19+
}}
20+
>
21+
<Button style={{ padding: '5px' }} onClick={close}>
22+
[X]
23+
</Button>
24+
</div>
25+
);
26+
};
27+
28+
export default function About({
29+
setVisible,
30+
}: {
31+
setVisible: (show: boolean) => void;
32+
}) {
33+
const [showTos, setShowTos] = useState<boolean>(false);
34+
35+
if (showTos) {
36+
return <Tos setVisible={setShowTos} />;
37+
}
38+
39+
return (
40+
<AboutPanel>
41+
<CloseButton setVisible={setVisible} />
42+
<BannerContainer>
43+
<Banner>{'{paste}'}</Banner>
44+
</BannerContainer>
45+
<p>
46+
<b>paste is a simple web app for writing & sharing code</b>. It's a
47+
different take on conventional pastebin sites like pastebin.com or
48+
hastebin.
49+
</p>
50+
{window.location.hostname === 'pastes.dev' && (
51+
<>
52+
<p>
53+
<b>pastes.dev</b> is the official, publicly accessible paste
54+
instance, and can be used by anyone, subject to the{' '}
55+
<a
56+
href="#"
57+
onClick={e => {
58+
setShowTos(true);
59+
e.preventDefault();
60+
}}
61+
>
62+
Terms of Service
63+
</a>
64+
.
65+
</p>
66+
<p>
67+
To access pastes.dev programmatically, please use the{' '}
68+
<a href="https://github.com/lucko/paste#readme" target="_blank">
69+
API
70+
</a>
71+
. :)
72+
</p>
73+
<p>
74+
Please{' '}
75+
<b>
76+
<a
77+
href="#"
78+
onClick={e => {
79+
setShowTos(true);
80+
e.preventDefault();
81+
}}
82+
>
83+
report
84+
</a>
85+
</b>{' '}
86+
illegal, malicious, or abusive content so it can be removed.
87+
</p>
88+
</>
89+
)}
90+
<p style={{ textAlign: 'center' }}>
91+
<a href="https://github.com/lucko/paste" target="_blank">
92+
paste
93+
</a>{' '}
94+
is free & open source on GitHub.
95+
<br />
96+
Copyright &copy; 2021-{new Date().getFullYear()}{' '}
97+
<a href="https://github.com/lucko" target="_blank">
98+
lucko
99+
</a>{' '}
100+
& other paste{' '}
101+
<a
102+
href="https://github.com/lucko/paste/graphs/contributors"
103+
target="_blank"
104+
>
105+
contributors
106+
</a>
107+
.
108+
</p>
109+
</AboutPanel>
110+
);
111+
}
112+
113+
const Tos = ({ setVisible }: { setVisible: (show: boolean) => void }) => {
114+
return (
115+
<AboutPanel>
116+
<CloseButton setVisible={setVisible} />
117+
<h1>Terms of Service</h1>
118+
<p>
119+
Welcome to pastes.dev. By using this service, you agree to the following
120+
terms:
121+
</p>
122+
<ol>
123+
<li>
124+
<b>No Illegal Use:</b> You may not use pastes.dev to share, store, or
125+
distribute any content that is illegal, harmful, or violates any laws
126+
or regulations.
127+
</li>
128+
<li>
129+
<b>No Malicious Content:</b> Do not upload or share content intended
130+
to harm others, including but not limited to malware, phishing links,
131+
or personal data without consent.
132+
</li>
133+
<li>
134+
<b>Content Responsibility:</b> You are solely responsible for the
135+
content you post. We do not review content and are not liable for what
136+
users choose to share.
137+
</li>
138+
<li>
139+
<b>Moderation:</b> We reserve the right to remove any content at our
140+
discretion, and to restrict or terminate access to the service for
141+
abuse or violations of these terms.
142+
</li>
143+
<li>
144+
<b>No Guarantees:</b> This service is provided "as is" with no
145+
warranties. We do not guarantee uptime, data retention, or
146+
availability.
147+
</li>
148+
</ol>
149+
<p>
150+
By using pastes.dev, you accept these terms. If you do not agree, please
151+
do not use the service.
152+
</p>
153+
<p>
154+
<b>Reporting Abuse</b>
155+
<br />
156+
If you encounter illegal or malicious content, please report it by email
157+
to report-abuse {'<at>'} pastes.dev.
158+
</p>
159+
</AboutPanel>
160+
);
161+
};
162+
163+
const AboutPanel = styled.div`
164+
position: absolute;
165+
top: 50%;
166+
left: 50%;
167+
transform: translate(-50%, -50%);
168+
z-index: 99;
169+
max-width: 650px;
170+
171+
color: ${props => props.theme.primary};
172+
background-color: ${props => props.theme.secondary};
173+
174+
padding: 10px;
175+
`;
176+
177+
const BannerContainer = styled.div`
178+
display: flex;
179+
justify-content: center;
180+
`;
181+
182+
const Banner = styled.div`
183+
background-color: ${props => props.theme.background};
184+
color: ${props => props.theme.logo};
185+
border-radius: 20px;
186+
font-size: 70px;
187+
letter-spacing: -5px;
188+
padding: 10px;
189+
font-weight: bold;
190+
`;

src/components/Editor.tsx

Lines changed: 32 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
import { useEffect, useRef, useState } from 'react';
22
import { isMobile } from 'react-device-detect';
3-
import { ThemeProvider } from 'styled-components';
43

54
import usePreference from '../hooks/usePreference';
6-
import themes, { Themes } from '../style/themes';
5+
import { Themes } from '../style/themes.ts';
76
import EditorControls from './EditorControls';
87
import EditorGlobalStyle from './EditorGlobalStyle';
98
import EditorTextArea from './EditorTextArea';
@@ -14,6 +13,9 @@ export interface EditorProps {
1413
setActualContent: (value: string) => void;
1514
contentType?: string;
1615
pasteId?: string;
16+
theme: keyof Themes;
17+
setTheme: (value: keyof Themes) => void;
18+
setShowAbout: (value: boolean) => void;
1719
}
1820

1921
export type ResetFunction = () => void;
@@ -24,16 +26,14 @@ export default function Editor({
2426
setActualContent,
2527
contentType,
2628
pasteId,
29+
theme,
30+
setTheme,
31+
setShowAbout,
2732
}: EditorProps) {
2833
const [language, setLanguage] = useState<string>('plain');
2934
const [readOnly, setReadOnly] = useState<boolean>(isMobile && !!pasteId);
3035
const resetFunction = useRef<ResetFunction>(null);
3136

32-
const [theme, setTheme] = usePreference<keyof Themes>(
33-
'theme',
34-
'dark',
35-
pref => !!themes[pref]
36-
);
3737
const [fontSize, setFontSize, fontSizeCheck] = usePreference<number>(
3838
'fontsize',
3939
16,
@@ -61,33 +61,31 @@ export default function Editor({
6161

6262
return (
6363
<>
64-
<ThemeProvider theme={themes[theme]}>
65-
<EditorGlobalStyle />
66-
<EditorControls
67-
actualContent={actualContent}
68-
resetFunction={resetFunction}
69-
language={language}
70-
setLanguage={setLanguage}
71-
readOnly={readOnly}
72-
setReadOnly={setReadOnly}
73-
theme={theme}
74-
setTheme={setTheme}
75-
wordWrap={wordWrap}
76-
setWordWrap={setWordWrap}
77-
zoom={zoom}
78-
/>
79-
<EditorTextArea
80-
forcedContent={forcedContent}
81-
actualContent={actualContent}
82-
setActualContent={setActualContent}
83-
theme={themes[theme]}
84-
language={language}
85-
fontSize={fontSize}
86-
readOnly={readOnly}
87-
wordWrap={wordWrap}
88-
resetFunction={resetFunction}
89-
/>
90-
</ThemeProvider>
64+
<EditorGlobalStyle />
65+
<EditorControls
66+
actualContent={actualContent}
67+
resetFunction={resetFunction}
68+
language={language}
69+
setLanguage={setLanguage}
70+
readOnly={readOnly}
71+
setReadOnly={setReadOnly}
72+
theme={theme}
73+
setTheme={setTheme}
74+
wordWrap={wordWrap}
75+
setWordWrap={setWordWrap}
76+
zoom={zoom}
77+
setShowAbout={setShowAbout}
78+
/>
79+
<EditorTextArea
80+
forcedContent={forcedContent}
81+
actualContent={actualContent}
82+
setActualContent={setActualContent}
83+
language={language}
84+
fontSize={fontSize}
85+
readOnly={readOnly}
86+
wordWrap={wordWrap}
87+
resetFunction={resetFunction}
88+
/>
9189
</>
9290
);
9391
}

src/components/EditorControls.tsx

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ export interface EditorControlsProps {
2222
wordWrap: boolean;
2323
setWordWrap: (value: boolean) => void;
2424
zoom: (delta: number) => void;
25+
setShowAbout: (value: boolean) => void;
2526
}
2627

2728
export default function EditorControls({
@@ -36,6 +37,7 @@ export default function EditorControls({
3637
wordWrap,
3738
setWordWrap,
3839
zoom,
40+
setShowAbout,
3941
}: EditorControlsProps) {
4042
const [saving, setSaving] = useState<boolean>(false);
4143
const [recentlySaved, setRecentlySaved] = useState<boolean>(false);
@@ -44,6 +46,10 @@ export default function EditorControls({
4446
setRecentlySaved(false);
4547
}, [actualContent, language]);
4648

49+
const showAbout = useCallback(() => {
50+
setShowAbout(true);
51+
}, [setShowAbout]);
52+
4753
const save = useCallback(() => {
4854
if (!actualContent || recentlySaved) {
4955
return;
@@ -126,15 +132,7 @@ export default function EditorControls({
126132
setValue={setTheme}
127133
ids={Object.keys(themes) as (keyof Themes)[]}
128134
/>
129-
<Button
130-
className="optional"
131-
as="a"
132-
href="https://github.com/lucko/paste#readme"
133-
target="_blank"
134-
rel="noreferrer"
135-
>
136-
[about]
137-
</Button>
135+
<Button onClick={showAbout}>[about]</Button>
138136
</Section>
139137
</Header>
140138
);

0 commit comments

Comments
 (0)