diff --git a/src/App.tsx b/src/App.tsx index cf78e32..cfffa93 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,5 +1,9 @@ import { useEffect, useState } from 'react'; +import { ThemeProvider } from 'styled-components'; +import About from './components/About.tsx'; import Editor from './components/Editor'; +import usePreference from './hooks/usePreference.ts'; +import themes, { Themes } from './style/themes.ts'; import { loadFromBytebin } from './util/storage'; const INITIAL = Symbol(); @@ -14,6 +18,12 @@ export default function App() { const [forcedContent, setForcedContent] = useState(''); const [actualContent, setActualContent] = useState(''); const [contentType, setContentType] = useState(); + const [theme, setTheme] = usePreference( + 'theme', + 'dark', + pref => !!themes[pref] + ); + const [showAbout, setShowAbout] = useState(true); function setContent(content: string) { setActualContent(content); @@ -40,13 +50,19 @@ export default function App() { }, [pasteId, state]); return ( - + + + {showAbout && } + ); } diff --git a/src/components/About.tsx b/src/components/About.tsx new file mode 100644 index 0000000..3a9410f --- /dev/null +++ b/src/components/About.tsx @@ -0,0 +1,190 @@ +import { useCallback, useState } from 'react'; +import styled from 'styled-components'; +import Button from './Button.tsx'; + +const CloseButton = ({ + setVisible, +}: { + setVisible: (show: boolean) => void; +}) => { + const close = useCallback(() => { + setVisible(false); + }, [setVisible]); + return ( +
+ +
+ ); +}; + +export default function About({ + setVisible, +}: { + setVisible: (show: boolean) => void; +}) { + const [showTos, setShowTos] = useState(false); + + if (showTos) { + return ; + } + + return ( + + + + {'{paste}'} + +

+ paste is a simple web app for writing & sharing code. It's a + different take on conventional pastebin sites like pastebin.com or + hastebin. +

+ {window.location.hostname === 'pastes.dev' && ( + <> +

+ pastes.dev is the official, publicly accessible paste + instance, and can be used by anyone, subject to the{' '} + { + setShowTos(true); + e.preventDefault(); + }} + > + Terms of Service + + . +

+

+ To access pastes.dev programmatically, please use the{' '} + + API + + . :) +

+

+ Please{' '} + + { + setShowTos(true); + e.preventDefault(); + }} + > + report + + {' '} + illegal, malicious, or abusive content so it can be removed. +

+ + )} +

+ + paste + {' '} + is free & open source on GitHub. +
+ Copyright © 2021-{new Date().getFullYear()}{' '} + + lucko + {' '} + & other paste{' '} + + contributors + + . +

+
+ ); +} + +const Tos = ({ setVisible }: { setVisible: (show: boolean) => void }) => { + return ( + + +

Terms of Service

+

+ Welcome to pastes.dev. By using this service, you agree to the following + terms: +

+
    +
  1. + No Illegal Use: You may not use pastes.dev to share, store, or + distribute any content that is illegal, harmful, or violates any laws + or regulations. +
  2. +
  3. + No Malicious Content: Do not upload or share content intended + to harm others, including but not limited to malware, phishing links, + or personal data without consent. +
  4. +
  5. + Content Responsibility: You are solely responsible for the + content you post. We do not review content and are not liable for what + users choose to share. +
  6. +
  7. + Moderation: We reserve the right to remove any content at our + discretion, and to restrict or terminate access to the service for + abuse or violations of these terms. +
  8. +
  9. + No Guarantees: This service is provided "as is" with no + warranties. We do not guarantee uptime, data retention, or + availability. +
  10. +
+

+ By using pastes.dev, you accept these terms. If you do not agree, please + do not use the service. +

+

+ Reporting Abuse +
+ If you encounter illegal or malicious content, please report it by email + to report-abuse {''} pastes.dev. +

+
+ ); +}; + +const AboutPanel = styled.div` + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + z-index: 99; + max-width: 650px; + + color: ${props => props.theme.primary}; + background-color: ${props => props.theme.secondary}; + + padding: 10px; +`; + +const BannerContainer = styled.div` + display: flex; + justify-content: center; +`; + +const Banner = styled.div` + background-color: ${props => props.theme.background}; + color: ${props => props.theme.logo}; + border-radius: 20px; + font-size: 70px; + letter-spacing: -5px; + padding: 10px; + font-weight: bold; +`; diff --git a/src/components/Editor.tsx b/src/components/Editor.tsx index 5684aca..c16b606 100644 --- a/src/components/Editor.tsx +++ b/src/components/Editor.tsx @@ -1,9 +1,8 @@ import { useEffect, useRef, useState } from 'react'; import { isMobile } from 'react-device-detect'; -import { ThemeProvider } from 'styled-components'; import usePreference from '../hooks/usePreference'; -import themes, { Themes } from '../style/themes'; +import { Themes } from '../style/themes.ts'; import EditorControls from './EditorControls'; import EditorGlobalStyle from './EditorGlobalStyle'; import EditorTextArea from './EditorTextArea'; @@ -14,6 +13,9 @@ export interface EditorProps { setActualContent: (value: string) => void; contentType?: string; pasteId?: string; + theme: keyof Themes; + setTheme: (value: keyof Themes) => void; + setShowAbout: (value: boolean) => void; } export type ResetFunction = () => void; @@ -24,16 +26,14 @@ export default function Editor({ setActualContent, contentType, pasteId, + theme, + setTheme, + setShowAbout, }: EditorProps) { const [language, setLanguage] = useState('plain'); const [readOnly, setReadOnly] = useState(isMobile && !!pasteId); const resetFunction = useRef(null); - const [theme, setTheme] = usePreference( - 'theme', - 'dark', - pref => !!themes[pref] - ); const [fontSize, setFontSize, fontSizeCheck] = usePreference( 'fontsize', 16, @@ -61,33 +61,31 @@ export default function Editor({ return ( <> - - - - - + + + ); } diff --git a/src/components/EditorControls.tsx b/src/components/EditorControls.tsx index eb68c3e..10160ed 100644 --- a/src/components/EditorControls.tsx +++ b/src/components/EditorControls.tsx @@ -22,6 +22,7 @@ export interface EditorControlsProps { wordWrap: boolean; setWordWrap: (value: boolean) => void; zoom: (delta: number) => void; + setShowAbout: (value: boolean) => void; } export default function EditorControls({ @@ -36,6 +37,7 @@ export default function EditorControls({ wordWrap, setWordWrap, zoom, + setShowAbout, }: EditorControlsProps) { const [saving, setSaving] = useState(false); const [recentlySaved, setRecentlySaved] = useState(false); @@ -44,6 +46,10 @@ export default function EditorControls({ setRecentlySaved(false); }, [actualContent, language]); + const showAbout = useCallback(() => { + setShowAbout(true); + }, [setShowAbout]); + const save = useCallback(() => { if (!actualContent || recentlySaved) { return; @@ -126,15 +132,7 @@ export default function EditorControls({ setValue={setTheme} ids={Object.keys(themes) as (keyof Themes)[]} /> - + ); diff --git a/src/components/EditorTextArea.tsx b/src/components/EditorTextArea.tsx index 5bd7514..9992843 100644 --- a/src/components/EditorTextArea.tsx +++ b/src/components/EditorTextArea.tsx @@ -13,7 +13,7 @@ import { useRef, useState, } from 'react'; -import styled from 'styled-components'; +import styled, { useTheme } from 'styled-components'; import themes, { Theme } from '../style/themes'; import type { editor } from 'monaco-editor'; @@ -58,7 +58,6 @@ export interface EditorTextAreaProps { forcedContent: string; actualContent: string; setActualContent: (value: string) => void; - theme: Theme; language: string; fontSize: number; readOnly: boolean; @@ -70,7 +69,6 @@ export default function EditorTextArea({ forcedContent, actualContent, setActualContent, - theme, language, fontSize, readOnly, @@ -81,6 +79,7 @@ export default function EditorTextArea({ const [monaco, setMonaco] = useState(); const [selected, toggleSelected] = useSelectedLine(); const editorAreaRef = useRef(null); + const theme = useTheme(); useLineNumberMagic( editorAreaRef, diff --git a/src/style/themes.ts b/src/style/themes.ts index 6c76f72..2a9d426 100644 --- a/src/style/themes.ts +++ b/src/style/themes.ts @@ -15,6 +15,7 @@ export interface Theme { secondary: Color; highlight: Color; background: Color; + logo: Color; lightOrDark: 'light' | 'dark'; highlightedLine: { color: Color; @@ -43,6 +44,7 @@ const themes: Themes = { secondary: '#010409', // canvas.inset highlight: '#161b22', // canvas.overlay background: '#0d1117', // canvas.default + logo: '#d2a8ff', lightOrDark: 'dark', highlightedLine: { @@ -85,6 +87,7 @@ const themes: Themes = { secondary: '#022550', highlight: '#36368c', background: '#ffffff', + logo: '#022550', lightOrDark: 'light', highlightedLine: { @@ -127,6 +130,7 @@ const themes: Themes = { secondary: '#383a59', highlight: '#44475a', background: '#282a36', + logo: '#BD93F9', // purple lightOrDark: 'dark', highlightedLine: { color: '#586e75', @@ -149,6 +153,7 @@ const themes: Themes = { secondary: '#222218', highlight: '#49483E', background: '#272822', + logo: '#f92672', // red lightOrDark: 'dark', highlightedLine: { color: '#49483E', @@ -171,6 +176,7 @@ const themes: Themes = { secondary: '#073642', // base02 highlight: '#002b36', // base03 background: '#002B36', // base03 + logo: '#dc322f', // red lightOrDark: 'dark', highlightedLine: { color: '#93a1a1', // base1 @@ -193,6 +199,7 @@ const themes: Themes = { secondary: '#eee8d5', // base2 highlight: '#FDF6E3', // base3 background: '#FDF6E3', // base3 + logo: '#dc322f', // red lightOrDark: 'light', highlightedLine: { color: '#586e75', // base01 @@ -380,6 +387,7 @@ export function createCatppuccinTheme(flavor: CatppuccinFlavor): Theme { color: color(flavor.colors.rosewater), backgroundColor: color(flavor.colors.surface2), }, + logo: color(flavor.colors.mauve), editor: editorTheme, }; }