Browse Source
* chore(js): be stricter about dead code warnings * chore(js): remove dead code and unused exports * rebase * chore: remove unused files * chore(deps): remove unused prop-types dep * chore(js): remove unused function * chore(deps): remove + check unused deps * chore(js): remove unused exports. Closes #3036pull/3039/head
55 changed files with 1187 additions and 1071 deletions
@ -0,0 +1,72 @@
@@ -0,0 +1,72 @@
|
||||
{ |
||||
"ignore": [ |
||||
"**/.eslintrc.js", |
||||
".storybook/**", |
||||
"**/*config.?s", |
||||
"**/*mock.?s", |
||||
"**/*fixture.?s", |
||||
"next-env.d.ts", |
||||
"public/**" |
||||
], |
||||
"ignoreDependencies": [ |
||||
"@fontsource/inter", |
||||
"@fontsource/poppins", |
||||
"@next/bundle-analyzer", |
||||
"autoprefixer", |
||||
"webpack-deadcode-plugin", |
||||
"yaml", |
||||
"postcss-flexbugs-fixes", |
||||
"sharp", |
||||
"next-with-less", |
||||
"next-pwa", |
||||
"workbox-precaching", |
||||
"workbox-window", |
||||
"@storybook/addon-a11y", |
||||
"@storybook/addon-docs", |
||||
"@storybook/addon-essentials", |
||||
"@storybook/addon-links", |
||||
"@storybook/addon-postcss", |
||||
"@storybook/addon-viewport", |
||||
"@storybook/builder-webpack5", |
||||
"@storybook/cli", |
||||
"@storybook/manager-webpack5", |
||||
"@storybook/mdx2-csf", |
||||
"@storybook/preset-scss", |
||||
"@mdx-js/react", |
||||
"@storybook/testing-library", |
||||
"@svgr/webpack", |
||||
"@types/jest", |
||||
"@types/markdown-it", |
||||
"@types/prop-types", |
||||
"@typescript-eslint/eslint-plugin", |
||||
"@typescript-eslint/parser", |
||||
"babel-loader", |
||||
"chromatic", |
||||
"css-loader", |
||||
"cypress", |
||||
"eslint-config-airbnb", |
||||
"eslint-config-next", |
||||
"eslint-config-prettier", |
||||
"eslint-plugin-import", |
||||
"eslint-plugin-jsx-a11y", |
||||
"eslint-plugin-prettier", |
||||
"eslint-plugin-react", |
||||
"eslint-plugin-react-hooks", |
||||
"eslint-plugin-storybook", |
||||
"handlebars", |
||||
"html-webpack-plugin", |
||||
"install", |
||||
"less", |
||||
"less-loader", |
||||
"mdx-mermaid", |
||||
"mermaid", |
||||
"prettier", |
||||
"sass-loader", |
||||
"sb", |
||||
"storybook-addon-designs", |
||||
"storybook-addon-fetch-mock", |
||||
"storybook-preset-less", |
||||
"style-loader", |
||||
"ts-jest" |
||||
] |
||||
} |
@ -1,71 +0,0 @@
@@ -1,71 +0,0 @@
|
||||
// Note: references to "yp" in the app are likely related to Owncast Directory
|
||||
import React, { useState, useContext, useEffect, FC } from 'react'; |
||||
import { Typography } from 'antd'; |
||||
|
||||
import { ToggleSwitch } from './ToggleSwitch'; |
||||
import { ServerStatusContext } from '../../utils/server-status-context'; |
||||
import { FIELD_PROPS_NSFW, FIELD_PROPS_YP } from '../../utils/config-constants'; |
||||
|
||||
const { Title } = Typography; |
||||
|
||||
// eslint-disable-next-line import/prefer-default-export
|
||||
export const EditYPDetails: FC = () => { |
||||
const [formDataValues, setFormDataValues] = useState(null); |
||||
|
||||
const serverStatusData = useContext(ServerStatusContext); |
||||
const { serverConfig } = serverStatusData || {}; |
||||
|
||||
const { yp, instanceDetails } = serverConfig; |
||||
const { nsfw } = instanceDetails; |
||||
const { enabled, instanceUrl } = yp; |
||||
|
||||
useEffect(() => { |
||||
setFormDataValues({ |
||||
...yp, |
||||
enabled, |
||||
nsfw, |
||||
}); |
||||
}, [yp, instanceDetails]); |
||||
|
||||
const hasInstanceUrl = instanceUrl !== ''; |
||||
if (!formDataValues) { |
||||
return null; |
||||
} |
||||
return ( |
||||
<div className="config-directory-details-form"> |
||||
<Title level={3} className="section-title"> |
||||
Owncast Directory Settings |
||||
</Title> |
||||
|
||||
<p className="description"> |
||||
Would you like to appear in the{' '} |
||||
<a href="https://directory.owncast.online" target="_blank" rel="noreferrer"> |
||||
<strong>Owncast Directory</strong> |
||||
</a> |
||||
? |
||||
</p> |
||||
|
||||
<p style={{ backgroundColor: 'black', fontSize: '.75rem', padding: '5px' }}> |
||||
<em> |
||||
NOTE: You will need to have a URL specified in the <code>Instance URL</code> field to be |
||||
able to use this. |
||||
</em> |
||||
</p> |
||||
|
||||
<div className="config-yp-container"> |
||||
<ToggleSwitch |
||||
fieldName="enabled" |
||||
{...FIELD_PROPS_YP} |
||||
checked={formDataValues.enabled} |
||||
disabled={!hasInstanceUrl} |
||||
/> |
||||
<ToggleSwitch |
||||
fieldName="nsfw" |
||||
{...FIELD_PROPS_NSFW} |
||||
checked={formDataValues.nsfw} |
||||
disabled={!hasInstanceUrl} |
||||
/> |
||||
</div> |
||||
</div> |
||||
); |
||||
}; |
@ -1,27 +0,0 @@
@@ -1,27 +0,0 @@
|
||||
import { Tooltip } from 'antd'; |
||||
import dynamic from 'next/dynamic'; |
||||
import { FC } from 'react'; |
||||
|
||||
// Lazy loaded components
|
||||
|
||||
const InfoCircleOutlined = dynamic(() => import('@ant-design/icons/InfoCircleOutlined'), { |
||||
ssr: false, |
||||
}); |
||||
|
||||
export type InfoTipProps = { |
||||
tip: string | null; |
||||
}; |
||||
|
||||
export const InfoTip: FC<InfoTipProps> = ({ tip }) => { |
||||
if (tip === '' || tip === null) { |
||||
return null; |
||||
} |
||||
|
||||
return ( |
||||
<span className="info-tip"> |
||||
<Tooltip title={tip}> |
||||
<InfoCircleOutlined /> |
||||
</Tooltip> |
||||
</span> |
||||
); |
||||
}; |
@ -1,31 +0,0 @@
@@ -1,31 +0,0 @@
|
||||
import { Table, Typography } from 'antd'; |
||||
import { FC } from 'react'; |
||||
|
||||
const { Title } = Typography; |
||||
|
||||
export type KeyValueTableProps = { |
||||
title: string; |
||||
data: any; |
||||
}; |
||||
|
||||
export const KeyValueTable: FC<KeyValueTableProps> = ({ title, data }) => { |
||||
const columns = [ |
||||
{ |
||||
title: 'Name', |
||||
dataIndex: 'name', |
||||
key: 'name', |
||||
}, |
||||
{ |
||||
title: 'Value', |
||||
dataIndex: 'value', |
||||
key: 'value', |
||||
}, |
||||
]; |
||||
|
||||
return ( |
||||
<> |
||||
<Title level={2}>{title}</Title> |
||||
<Table pagination={false} columns={columns} dataSource={data} rowKey="name" /> |
||||
</> |
||||
); |
||||
}; |
@ -1,29 +0,0 @@
@@ -1,29 +0,0 @@
|
||||
import { CSSProperties, FC } from 'react'; |
||||
|
||||
export type ModIconProps = { |
||||
style?: CSSProperties; |
||||
fill?: string; |
||||
stroke?: string; |
||||
}; |
||||
|
||||
export const ModIcon: FC<ModIconProps> = ({ |
||||
style = { width: '1rem', height: '1rem' }, |
||||
fill = 'none', |
||||
stroke = 'var(--color-owncast-gray-300)', |
||||
}: ModIconProps) => ( |
||||
<svg |
||||
fill={fill} |
||||
stroke={stroke} |
||||
style={style} |
||||
viewBox="0 0 24 24" |
||||
xmlns="http://www.w3.org/2000/svg" |
||||
> |
||||
<title>This user has moderation rights</title> |
||||
<path |
||||
strokeLinecap="round" |
||||
strokeLinejoin="round" |
||||
strokeWidth={2} |
||||
d="M9 12l2 2 4-4m5.618-4.016A11.955 11.955 0 0112 2.944a11.955 11.955 0 01-8.618 3.04A12.02 12.02 0 003 9c0 5.591 3.824 10.29 9 11.622 5.176-1.332 9-6.03 9-11.622 0-1.042-.133-2.052-.382-3.016z" |
||||
/> |
||||
</svg> |
||||
); |
File diff suppressed because it is too large
Load Diff
@ -1,78 +1 @@
@@ -1,78 +1 @@
|
||||
// misc constants used throughout the app
|
||||
|
||||
export const URL_STATUS = `/api/status`; |
||||
export const URL_CHAT_HISTORY = `/api/chat`; |
||||
export const URL_CUSTOM_EMOJIS = `/api/emoji`; |
||||
export const URL_CONFIG = `/api/config`; |
||||
export const URL_VIEWER_PING = `/api/ping`; |
||||
|
||||
// inline moderation actions
|
||||
export const URL_HIDE_MESSAGE = `/api/chat/messagevisibility`; |
||||
export const URL_BAN_USER = `/api/chat/users/setenabled`; |
||||
|
||||
// TODO: This directory is customizable in the config. So we should expose this via the config API.
|
||||
export const URL_STREAM = `/hls/stream.m3u8`; |
||||
// export const URL_WEBSOCKET = `${location.protocol === 'https:' ? 'wss' : 'ws'}://${
|
||||
// location.host
|
||||
// }/ws`;
|
||||
export const URL_CHAT_REGISTRATION = `/api/chat/register`; |
||||
export const URL_FOLLOWERS = `/api/followers`; |
||||
export const URL_PLAYBACK_METRICS = `/api/metrics/playback`; |
||||
|
||||
export const URL_REGISTER_NOTIFICATION = `/api/notifications/register`; |
||||
export const URL_REGISTER_EMAIL_NOTIFICATION = `/api/notifications/register/email`; |
||||
export const URL_CHAT_INDIEAUTH_BEGIN = `/api/auth/indieauth`; |
||||
|
||||
export const TIMER_STATUS_UPDATE = 5000; // ms
|
||||
export const TIMER_DISABLE_CHAT_AFTER_OFFLINE = 5 * 60 * 1000; // 5 mins
|
||||
export const TIMER_STREAM_DURATION_COUNTER = 1000; |
||||
export const TEMP_IMAGE = |
||||
'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7'; |
||||
|
||||
export const OWNCAST_LOGO_LOCAL = '/img/logo.svg'; |
||||
|
||||
export const MESSAGE_OFFLINE = 'Stream is offline.'; |
||||
export const MESSAGE_ONLINE = 'Stream is online.'; |
||||
|
||||
export const URL_OWNCAST = 'https://owncast.online'; // used in footer
|
||||
export const PLAYER_VOLUME = 'owncast_volume'; |
||||
|
||||
export const KEY_ACCESS_TOKEN = 'owncast_access_token'; |
||||
export const KEY_EMBED_CHAT_ACCESS_TOKEN = 'owncast_embed_chat_access_token'; |
||||
export const KEY_USERNAME = 'owncast_username'; |
||||
export const KEY_CUSTOM_USERNAME_SET = 'owncast_custom_username_set'; |
||||
export const KEY_CHAT_DISPLAYED = 'owncast_chat'; |
||||
export const KEY_CHAT_FIRST_MESSAGE_SENT = 'owncast_first_message_sent'; |
||||
export const CHAT_INITIAL_PLACEHOLDER_TEXT = 'Type here to chat, no account necessary.'; |
||||
export const CHAT_PLACEHOLDER_TEXT = 'Message'; |
||||
export const CHAT_PLACEHOLDER_OFFLINE = 'Chat is offline.'; |
||||
export const CHAT_MAX_MESSAGE_LENGTH = 500; |
||||
export const EST_SOCKET_PAYLOAD_BUFFER = 512; |
||||
export const CHAT_CHAR_COUNT_BUFFER = 20; |
||||
export const CHAT_OK_KEYCODES = [ |
||||
'ArrowLeft', |
||||
'ArrowUp', |
||||
'ArrowRight', |
||||
'ArrowDown', |
||||
'Shift', |
||||
'Meta', |
||||
'Alt', |
||||
'Delete', |
||||
'Backspace', |
||||
]; |
||||
export const CHAT_KEY_MODIFIERS = ['Control', 'Shift', 'Meta', 'Alt']; |
||||
export const MESSAGE_JUMPTOBOTTOM_BUFFER = 500; |
||||
|
||||
// app styling
|
||||
export const WIDTH_SINGLE_COL = 780; |
||||
export const HEIGHT_SHORT_WIDE = 500; |
||||
export const ORIENTATION_PORTRAIT = 'portrait'; |
||||
export const ORIENTATION_LANDSCAPE = 'landscape'; |
||||
|
||||
// localstorage keys
|
||||
export const HAS_DISPLAYED_NOTIFICATION_MODAL_KEY = 'HAS_DISPLAYED_NOTIFICATION_MODAL'; |
||||
export const USER_VISIT_COUNT_KEY = 'USER_VISIT_COUNT'; |
||||
export const USER_DISMISSED_ANNOYING_NOTIFICATION_POPUP_KEY = |
||||
'USER_DISMISSED_ANNOYING_NOTIFICATION_POPUP_KEY'; |
||||
|
||||
export const DYNAMIC_PADDING_VALUE = '320px'; |
||||
|
@ -1,32 +0,0 @@
@@ -1,32 +0,0 @@
|
||||
import { useState, useEffect } from 'react'; |
||||
|
||||
export default function useWindowSize() { |
||||
// Initialize state with undefined width/height so server and client renders match
|
||||
// Learn more here: https://joshwcomeau.com/react/the-perils-of-rehydration/
|
||||
const [windowSize, setWindowSize] = useState({ |
||||
width: undefined, |
||||
height: undefined, |
||||
}); |
||||
|
||||
useEffect(() => { |
||||
// Handler to call on window resize
|
||||
function handleResize() { |
||||
// Set window width/height to state
|
||||
setWindowSize({ |
||||
width: window.innerWidth, |
||||
height: window.innerHeight, |
||||
}); |
||||
} |
||||
|
||||
// Add event listener
|
||||
window.addEventListener('resize', handleResize); |
||||
|
||||
// Call handler right away so state gets updated with initial window size
|
||||
handleResize(); |
||||
|
||||
// Remove event listener on cleanup
|
||||
return () => window.removeEventListener('resize', handleResize); |
||||
}, []); // Empty array ensures that effect is only run on mount
|
||||
|
||||
return windowSize; |
||||
} |
Loading…
Reference in new issue