UI/UX
disable file input while awaiting publish add spinner to publishes in sidebar add spinner and Publishing title on Publish page add WebUploadList to Publishes add WebUploadItem - thumb - name - progress bar - abort button beforeunload prevent closing tab / navigation enforce and notify about publish size limit 6 outstanding flow complaints
This commit is contained in:
parent
dc1863890e
commit
3cc69ddaf0
22 changed files with 260 additions and 28 deletions
2
flow-typed/web-file.js
vendored
2
flow-typed/web-file.js
vendored
|
@ -1,4 +1,6 @@
|
|||
declare type WebFile = {
|
||||
name: string,
|
||||
title?: string,
|
||||
path?: string,
|
||||
size?: string,
|
||||
}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import { HEADERS, Lbry } from 'lbry-redux';
|
||||
import { Lbry } from 'lbry-redux';
|
||||
import apiPublishCallViaWeb from './publish';
|
||||
import { X_LBRY_AUTH_TOKEN } from 'constants/token';
|
||||
|
||||
export const SDK_API_URL = process.env.SDK_API_URL || 'https://api.lbry.tv/api/v1/proxy';
|
||||
|
||||
Lbry.setDaemonConnectionString(SDK_API_URL);
|
||||
|
||||
Lbry.setOverride(
|
||||
|
@ -11,8 +11,8 @@ Lbry.setOverride(
|
|||
new Promise((resolve, reject) => {
|
||||
apiPublishCallViaWeb(
|
||||
SDK_API_URL,
|
||||
Lbry.getApiRequestHeaders() && Object.keys(Lbry.getApiRequestHeaders()).includes(HEADERS.AUTH_TOKEN)
|
||||
? Lbry.getApiRequestHeaders()[HEADERS.AUTH_TOKEN]
|
||||
Lbry.getApiRequestHeaders() && Object.keys(Lbry.getApiRequestHeaders()).includes(X_LBRY_AUTH_TOKEN)
|
||||
? Lbry.getApiRequestHeaders()[X_LBRY_AUTH_TOKEN]
|
||||
: '',
|
||||
'publish',
|
||||
params,
|
||||
|
|
|
@ -1,5 +1,13 @@
|
|||
// @flow
|
||||
import { HEADERS } from 'lbry-redux';
|
||||
/*
|
||||
https://api.lbry.tv/api/v1/proxy currently expects publish to consist
|
||||
of a multipart/form-data POST request with:
|
||||
- 'file' binary
|
||||
- 'json_payload' collection of publish params to be passed to the server's sdk.
|
||||
*/
|
||||
import { X_LBRY_AUTH_TOKEN } from 'constants/token';
|
||||
import { doUpdateUploadProgress } from 'lbryinc';
|
||||
|
||||
// A modified version of Lbry.apiCall that allows
|
||||
// to perform calling methods at arbitrary urls
|
||||
// and pass form file fields
|
||||
|
@ -26,27 +34,34 @@ export default function apiPublishCallViaWeb(
|
|||
body.append('file', fileField);
|
||||
body.append('json_payload', jsonPayload);
|
||||
|
||||
function makeRequest(connectionString, method, token, body) {
|
||||
function makeRequest(connectionString, method, token, body, params) {
|
||||
return new Promise((resolve, reject) => {
|
||||
let xhr = new XMLHttpRequest();
|
||||
xhr.open(method, connectionString);
|
||||
xhr.setRequestHeader(HEADERS.AUTH_TOKEN, token);
|
||||
xhr.setRequestHeader(X_LBRY_AUTH_TOKEN, token);
|
||||
xhr.responseType = 'json';
|
||||
xhr.upload.onprogress = e => {
|
||||
let percentComplete = Math.ceil((e.loaded / e.total) * 100);
|
||||
console.log(percentComplete); // put your upload state update here
|
||||
window.store.dispatch(doUpdateUploadProgress(percentComplete, params, xhr));
|
||||
};
|
||||
xhr.onload = () => {
|
||||
window.store.dispatch(doUpdateUploadProgress(undefined, params));
|
||||
resolve(xhr);
|
||||
};
|
||||
xhr.onerror = () => {
|
||||
reject({ status: xhr.status, statusText: xhr.statusText });
|
||||
window.store.dispatch(doUpdateUploadProgress(undefined, params));
|
||||
reject(new Error(__('There was a problem with your upload')));
|
||||
};
|
||||
|
||||
xhr.onabort = () => {
|
||||
window.store.dispatch(doUpdateUploadProgress(undefined, params));
|
||||
reject(new Error(__('You aborted your publish upload')));
|
||||
};
|
||||
xhr.send(body);
|
||||
});
|
||||
}
|
||||
|
||||
return makeRequest(connectionString, 'POST', token, body)
|
||||
return makeRequest(connectionString, 'POST', token, body, params)
|
||||
.then(xhr => {
|
||||
let error;
|
||||
if (xhr) {
|
||||
|
@ -55,7 +70,7 @@ export default function apiPublishCallViaWeb(
|
|||
} else if (xhr.statusText) {
|
||||
error = new Error(xhr.statusText);
|
||||
} else {
|
||||
error = new Error('Upload likely timed out. Try a smaller file while we work on this.');
|
||||
error = new Error(__('Upload likely timed out. Try a smaller file while we work on this.'));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@ import {
|
|||
doFetchAccessToken,
|
||||
selectAccessToken,
|
||||
selectGetSyncErrorMessage,
|
||||
selectUploadCount,
|
||||
} from 'lbryinc';
|
||||
import { doFetchTransactions, doFetchChannelListMine, selectBalance } from 'lbry-redux';
|
||||
import { makeSelectClientSetting, selectThemePath } from 'redux/selectors/settings';
|
||||
|
@ -26,6 +27,7 @@ const select = state => ({
|
|||
syncEnabled: makeSelectClientSetting(SETTINGS.ENABLE_SYNC)(state),
|
||||
syncError: selectGetSyncErrorMessage(state),
|
||||
accessToken: selectAccessToken(state),
|
||||
uploadCount: selectUploadCount(state),
|
||||
});
|
||||
|
||||
const perform = dispatch => ({
|
||||
|
|
|
@ -47,6 +47,7 @@ type Props = {
|
|||
checkSync: () => void,
|
||||
setSyncEnabled: boolean => void,
|
||||
syncEnabled: boolean,
|
||||
uploadCount: number,
|
||||
balance: ?number,
|
||||
accessToken: ?string,
|
||||
syncError: ?string,
|
||||
|
@ -68,6 +69,7 @@ function App(props: Props) {
|
|||
setSyncEnabled,
|
||||
syncEnabled,
|
||||
checkSync,
|
||||
uploadCount,
|
||||
balance,
|
||||
accessToken,
|
||||
history,
|
||||
|
@ -128,6 +130,16 @@ function App(props: Props) {
|
|||
});
|
||||
}, [balance, accessToken, hasDeterminedIfNewUser, setHasDeterminedIfNewUser]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!uploadCount) return;
|
||||
const handleBeforeUnload = event => {
|
||||
event.preventDefault();
|
||||
event.returnValue = 'magic';
|
||||
};
|
||||
window.addEventListener('beforeunload', handleBeforeUnload);
|
||||
return () => window.removeEventListener('beforeunload', handleBeforeUnload);
|
||||
}, [uploadCount]);
|
||||
|
||||
useEffect(() => {
|
||||
ReactModal.setAppElement(appRef.current);
|
||||
fetchAccessToken();
|
||||
|
|
|
@ -13,6 +13,8 @@ type Props = {
|
|||
fileLabel?: string,
|
||||
directoryLabel?: string,
|
||||
accept?: string,
|
||||
error?: string,
|
||||
disabled?: boolean,
|
||||
};
|
||||
|
||||
class FileSelector extends React.PureComponent<Props> {
|
||||
|
@ -48,7 +50,7 @@ class FileSelector extends React.PureComponent<Props> {
|
|||
input: ?HTMLInputElement;
|
||||
|
||||
render() {
|
||||
const { type, currentPath, label, fileLabel, directoryLabel, placeholder, accept } = this.props;
|
||||
const { type, currentPath, label, fileLabel, directoryLabel, placeholder, accept, error, disabled } = this.props;
|
||||
|
||||
const buttonLabel = type === 'file' ? fileLabel || __('Choose File') : directoryLabel || __('Choose Directory');
|
||||
const placeHolder = currentPath || placeholder;
|
||||
|
@ -58,10 +60,14 @@ class FileSelector extends React.PureComponent<Props> {
|
|||
label={label}
|
||||
webkitdirectory="true"
|
||||
className="form-field--copyable"
|
||||
error={error}
|
||||
disabled={disabled}
|
||||
type="text"
|
||||
readOnly="readonly"
|
||||
value={placeHolder || __('Choose a file')}
|
||||
inputButton={<Button button="primary" onClick={this.fileInputButton} label={buttonLabel} />}
|
||||
inputButton={
|
||||
<Button button="primary" disabled={disabled} onClick={this.fileInputButton} label={buttonLabel} />
|
||||
}
|
||||
/>
|
||||
<input
|
||||
type={'file'}
|
||||
|
|
|
@ -8,6 +8,7 @@ const select = state => ({
|
|||
filePath: makeSelectPublishFormValue('filePath')(state),
|
||||
isStillEditing: selectIsStillEditing(state),
|
||||
balance: selectBalance(state),
|
||||
publishing: makeSelectPublishFormValue('publishing')(state),
|
||||
});
|
||||
|
||||
const perform = dispatch => ({
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
// @flow
|
||||
import * as ICONS from 'constants/icons';
|
||||
import React from 'react';
|
||||
import React, { useState } from 'react';
|
||||
import { regexInvalidURI } from 'lbry-redux';
|
||||
import FileSelector from 'component/common/file-selector';
|
||||
import Button from 'component/button';
|
||||
import Card from 'component/common/card';
|
||||
import Spinner from 'component/spinner';
|
||||
|
||||
type Props = {
|
||||
name: ?string,
|
||||
|
@ -13,10 +14,14 @@ type Props = {
|
|||
balance: number,
|
||||
updatePublishForm: ({}) => void,
|
||||
disabled: boolean,
|
||||
publishing: boolean,
|
||||
};
|
||||
|
||||
function PublishFile(props: Props) {
|
||||
const { name, balance, filePath, isStillEditing, updatePublishForm, disabled } = props;
|
||||
const { name, balance, filePath, isStillEditing, updatePublishForm, disabled, publishing } = props;
|
||||
|
||||
// This is basically for displaying the 500mb limit
|
||||
const [fileError, setFileError] = useState('');
|
||||
|
||||
let currentFile = '';
|
||||
if (filePath) {
|
||||
|
@ -30,29 +35,57 @@ function PublishFile(props: Props) {
|
|||
function handleFileChange(file: WebFile) {
|
||||
// if electron, we'll set filePath to the path string because SDK is handling publishing.
|
||||
// if web, we set the filePath (dumb name) to the File() object
|
||||
// file.path will be undefined from web due to browser security, so it will default to the File Object.
|
||||
// File.path will be undefined from web due to browser security, so it will default to the File Object.
|
||||
|
||||
// @if TARGET='web'
|
||||
// we only need to enforce file sizes on 'web'
|
||||
const PUBLISH_SIZE_LIMIT: number = 512000000;
|
||||
if (typeof file !== 'string') {
|
||||
if (file && file.size && Number(file.size) > PUBLISH_SIZE_LIMIT) {
|
||||
setFileError('File uploads currently limited to 500MB. Download the app for unlimited publishing.');
|
||||
updatePublishForm({ filePath: '', name: '' });
|
||||
return;
|
||||
} else {
|
||||
setFileError('');
|
||||
}
|
||||
}
|
||||
// @endif
|
||||
const publishFormParams: { filePath: string | WebFile, name?: string } = {
|
||||
filePath: file.path || file,
|
||||
name: file.name,
|
||||
};
|
||||
const parsedFileName = file.name.replace(regexInvalidURI, '');
|
||||
|
||||
publishFormParams.name = parsedFileName.replace(' ', '-');
|
||||
|
||||
updatePublishForm(publishFormParams);
|
||||
}
|
||||
|
||||
let title;
|
||||
if (publishing) {
|
||||
title = (
|
||||
<span>
|
||||
{__('Publishing')}
|
||||
<Spinner type={'small'} />
|
||||
</span>
|
||||
);
|
||||
} else {
|
||||
title = isStillEditing ? __('Edit') : __('Publish');
|
||||
}
|
||||
return (
|
||||
<Card
|
||||
icon={ICONS.PUBLISH}
|
||||
disabled={disabled || balance === 0}
|
||||
title={isStillEditing ? __('Edit') : __('Publish')}
|
||||
title={title}
|
||||
subtitle={
|
||||
isStillEditing ? __('You are currently editing a claim.') : __('Publish something totally wacky and wild.')
|
||||
}
|
||||
actions={
|
||||
<React.Fragment>
|
||||
<FileSelector currentPath={currentFile} onFileChosen={handleFileChange} />
|
||||
<FileSelector
|
||||
disabled={disabled}
|
||||
currentPath={currentFile}
|
||||
onFileChosen={handleFileChange}
|
||||
error={fileError}
|
||||
/>
|
||||
{!isStillEditing && (
|
||||
<p className="help">
|
||||
{__('For video content, use MP4s in H264/AAC format for best compatibility.')}{' '}
|
||||
|
|
|
@ -1,4 +1,12 @@
|
|||
// @flow
|
||||
|
||||
/*
|
||||
On submit, this component calls publish, which dispatches doPublishDesktop.
|
||||
doPublishDesktop calls lbry-redux Lbry publish method using lbry-redux publish state as params.
|
||||
Publish simply instructs the SDK to find the file path on disk and publish it with the provided metadata.
|
||||
On web, the Lbry publish method call is overridden in platform/web/api-setup, using a function in platform/web/publish.
|
||||
File upload is carried out in the background by that function.
|
||||
*/
|
||||
import React, { useEffect, Fragment } from 'react';
|
||||
import { CHANNEL_NEW, CHANNEL_ANONYMOUS } from 'constants/claim';
|
||||
import { buildURI, isURIValid, isNameValid, THUMBNAIL_STATUSES } from 'lbry-redux';
|
||||
|
@ -122,7 +130,7 @@ function PublishForm(props: Props) {
|
|||
|
||||
return (
|
||||
<Fragment>
|
||||
<PublishFile disabled={formDisabled}/>
|
||||
<PublishFile disabled={publishing} />
|
||||
<div className={classnames({ 'card--disabled': formDisabled })}>
|
||||
<PublishText disabled={formDisabled} />
|
||||
<Card actions={<SelectThumbnail />} />
|
||||
|
|
|
@ -24,7 +24,7 @@ function SelectAsset(props: Props) {
|
|||
const { onUpdate, assetName, currentValue, recommended } = props;
|
||||
const [assetSource, setAssetSource] = useState(SOURCE_URL);
|
||||
const [pathSelected, setPathSelected] = useState('');
|
||||
const [fileSelected, setFileSelected] = useState(null);
|
||||
const [fileSelected, setFileSelected] = useState('');
|
||||
const [uploadStatus, setUploadStatus] = useState(SPEECH_READY);
|
||||
|
||||
function doUploadAsset(file) {
|
||||
|
@ -95,7 +95,7 @@ function SelectAsset(props: Props) {
|
|||
button={'secondary'}
|
||||
onClick={() => {
|
||||
setPathSelected('');
|
||||
setFileSelected(null);
|
||||
setFileSelected('');
|
||||
}}
|
||||
>
|
||||
Clear
|
||||
|
|
|
@ -2,7 +2,7 @@ import * as SETTINGS from 'constants/settings';
|
|||
import { connect } from 'react-redux';
|
||||
import { selectSubscriptions } from 'redux/selectors/subscriptions';
|
||||
import { selectFollowedTags } from 'lbry-redux';
|
||||
import { selectUserEmail } from 'lbryinc';
|
||||
import { selectUserEmail, selectUploadCount } from 'lbryinc';
|
||||
import SideBar from './view';
|
||||
import { makeSelectClientSetting } from 'redux/selectors/settings';
|
||||
|
||||
|
@ -11,6 +11,7 @@ const select = state => ({
|
|||
followedTags: selectFollowedTags(state),
|
||||
language: makeSelectClientSetting(SETTINGS.LANGUAGE)(state), // trigger redraw on language change
|
||||
email: selectUserEmail(state),
|
||||
uploadCount: selectUploadCount(state),
|
||||
});
|
||||
|
||||
const perform = () => ({});
|
||||
|
|
|
@ -6,16 +6,18 @@ import Button from 'component/button';
|
|||
import Tag from 'component/tag';
|
||||
import StickyBox from 'react-sticky-box/dist/esnext';
|
||||
import 'css-doodle';
|
||||
import Spinner from 'component/spinner';
|
||||
|
||||
type Props = {
|
||||
subscriptions: Array<Subscription>,
|
||||
followedTags: Array<Tag>,
|
||||
email: ?string,
|
||||
obscureSideBar: boolean,
|
||||
uploadCount: number,
|
||||
};
|
||||
|
||||
function SideBar(props: Props) {
|
||||
const { subscriptions, followedTags, obscureSideBar } = props;
|
||||
const { subscriptions, followedTags, obscureSideBar, uploadCount } = props;
|
||||
function buildLink(path, label, icon, guide) {
|
||||
return {
|
||||
navigate: path ? `$/${path}` : '/',
|
||||
|
@ -52,7 +54,18 @@ function SideBar(props: Props) {
|
|||
...buildLink(PAGES.CHANNELS, __('Channels'), ICONS.CHANNEL),
|
||||
},
|
||||
{
|
||||
...buildLink(PAGES.PUBLISHED, __('Publishes'), ICONS.PUBLISH),
|
||||
...buildLink(
|
||||
PAGES.PUBLISHED,
|
||||
uploadCount ? (
|
||||
<span>
|
||||
{__('Publishes')}
|
||||
<Spinner type="small" />
|
||||
</span>
|
||||
) : (
|
||||
__('Publishes')
|
||||
),
|
||||
ICONS.PUBLISH
|
||||
),
|
||||
},
|
||||
].map(linkProps => (
|
||||
<li key={linkProps.label}>
|
||||
|
|
13
src/ui/component/webUploadList/index.js
Normal file
13
src/ui/component/webUploadList/index.js
Normal file
|
@ -0,0 +1,13 @@
|
|||
import { connect } from 'react-redux';
|
||||
import { selectCurrentUploads, selectUploadCount } from 'lbryinc';
|
||||
import WebUploadList from './view';
|
||||
|
||||
const select = state => ({
|
||||
currentUploads: selectCurrentUploads(state),
|
||||
uploadCount: selectUploadCount(state),
|
||||
});
|
||||
|
||||
export default connect(
|
||||
select,
|
||||
null
|
||||
)(WebUploadList);
|
41
src/ui/component/webUploadList/internal/web-upload-item.jsx
Normal file
41
src/ui/component/webUploadList/internal/web-upload-item.jsx
Normal file
|
@ -0,0 +1,41 @@
|
|||
// @flow
|
||||
import React from 'react';
|
||||
import Button from 'component/button';
|
||||
import CardMedia from 'component/cardMedia';
|
||||
type Props = {
|
||||
params: UpdatePublishFormData,
|
||||
progress: string,
|
||||
xhr?: () => void,
|
||||
};
|
||||
|
||||
export default function WebUploadItem(props: Props) {
|
||||
const { params, progress, xhr } = props;
|
||||
|
||||
return (
|
||||
<li className={'claim-preview'}>
|
||||
<CardMedia thumbnail={params.thumbnail_url} />
|
||||
<div className={'claim-preview-metadata'}>
|
||||
<div className="claim-preview-info">
|
||||
<div className="claim-preview-title">{params.title}</div>
|
||||
{xhr && (
|
||||
<div className="card__actions--inline">
|
||||
<Button
|
||||
button={'primary'}
|
||||
onClick={() => {
|
||||
xhr.abort();
|
||||
}}
|
||||
label={'abort'}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<h2>{params.name}</h2>
|
||||
<div className={'claim-upload__progress--outer'}>
|
||||
<div className={'claim-upload__progress--inner'} style={{ width: `${progress}%` }}>
|
||||
Uploading...
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
);
|
||||
}
|
37
src/ui/component/webUploadList/view.jsx
Normal file
37
src/ui/component/webUploadList/view.jsx
Normal file
|
@ -0,0 +1,37 @@
|
|||
// @flow
|
||||
import * as React from 'react';
|
||||
import Card from 'component/common/card';
|
||||
import WebUploadItem from './internal/web-upload-item';
|
||||
|
||||
export type UploadItem = {
|
||||
progess: string,
|
||||
params: UpdatePublishFormData,
|
||||
xhr?: { abort: () => void },
|
||||
};
|
||||
|
||||
type Props = {
|
||||
currentUploads: { [key: string]: UploadItem },
|
||||
uploadCount: ?number,
|
||||
};
|
||||
|
||||
export default function WebUploadList(props: Props) {
|
||||
const { currentUploads, uploadCount } = props;
|
||||
|
||||
return (
|
||||
!!uploadCount && (
|
||||
<div>
|
||||
<Card
|
||||
title={__('Currently Uploading')}
|
||||
subtitle={<span>{__('You are currently uploading one or more files for publish.')}</span>}
|
||||
body={
|
||||
<section>
|
||||
{Object.values(currentUploads).map(({ progress, params, xhr }) => (
|
||||
<WebUploadItem key={`upload${params.name}`} progress={progress} params={params} xhr={xhr} />
|
||||
))}
|
||||
</section>
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
);
|
||||
}
|
1
src/ui/constants/token.js
Normal file
1
src/ui/constants/token.js
Normal file
|
@ -0,0 +1 @@
|
|||
export const X_LBRY_AUTH_TOKEN = 'X-Lbry-Auth-Token';
|
|
@ -27,6 +27,12 @@ class ModalPublishSuccess extends React.PureComponent<Props> {
|
|||
navigate('/$/published');
|
||||
closeModal();
|
||||
}}
|
||||
confirmButtonLabel={'Show me!'}
|
||||
abortButtonLabel={'Thanks!'}
|
||||
onAborted={() => {
|
||||
clearPublish();
|
||||
closeModal();
|
||||
}}
|
||||
>
|
||||
<p>{__(`Your ${publishMessage} published to LBRY at the address`)}</p>
|
||||
<blockquote>{uri}</blockquote>
|
||||
|
|
|
@ -5,6 +5,7 @@ import ClaimList from 'component/claimList';
|
|||
import Page from 'component/page';
|
||||
import Paginate from 'component/common/paginate';
|
||||
import { PAGE_SIZE } from 'constants/claim';
|
||||
import WebUploadList from 'component/webUploadList';
|
||||
|
||||
type Props = {
|
||||
checkPendingPublishes: () => void,
|
||||
|
@ -25,6 +26,7 @@ function FileListPublished(props: Props) {
|
|||
|
||||
return (
|
||||
<Page notContained>
|
||||
<WebUploadList />
|
||||
{urls && urls.length ? (
|
||||
<div className="card">
|
||||
<ClaimList
|
||||
|
|
|
@ -21,6 +21,7 @@ import {
|
|||
homepageReducer,
|
||||
statsReducer,
|
||||
syncReducer,
|
||||
lbrytvReducer,
|
||||
} from 'lbryinc';
|
||||
import appReducer from 'redux/reducers/app';
|
||||
import availabilityReducer from 'redux/reducers/availability';
|
||||
|
@ -54,4 +55,5 @@ export default history =>
|
|||
user: userReducer,
|
||||
wallet: walletReducer,
|
||||
sync: syncReducer,
|
||||
lbrytv: lbrytvReducer,
|
||||
});
|
||||
|
|
|
@ -7,6 +7,8 @@ import path from 'path';
|
|||
import * as ACTIONS from 'constants/action_types';
|
||||
import * as MODALS from 'constants/modal_types';
|
||||
import * as PAGES from 'constants/pages';
|
||||
import { X_LBRY_AUTH_TOKEN } from 'constants/token';
|
||||
import * as SETTINGS from 'constants/settings';
|
||||
import {
|
||||
Lbry,
|
||||
doBalanceSubscribe,
|
||||
|
@ -437,8 +439,9 @@ export function doAnalyticsView(uri, timeToStart) {
|
|||
export function doSignIn() {
|
||||
return (dispatch, getState) => {
|
||||
// @if TARGET='web'
|
||||
const authToken = getAuthToken();
|
||||
Lbry.setApiHeader(HEADERS.AUTH_TOKEN, authToken);
|
||||
const { auth_token: authToken } = cookie.parse(document.cookie);
|
||||
Lbry.setApiHeader(X_LBRY_AUTH_TOKEN, authToken);
|
||||
|
||||
dispatch(doBalanceSubscribe());
|
||||
dispatch(doFetchChannelListMine());
|
||||
// @endif
|
||||
|
|
|
@ -198,3 +198,36 @@ $border-color--dark: var(--dm-color-04);
|
|||
flex: 1;
|
||||
font-size: var(--font-subtext);
|
||||
}
|
||||
|
||||
.claim-upload {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
position: relative;
|
||||
overflow: visible;
|
||||
padding: var(--spacing-medium);
|
||||
|
||||
.media__thumb {
|
||||
width: var(--file-list-thumbnail-width);
|
||||
flex-shrink: 0;
|
||||
margin-right: var(--spacing-medium);
|
||||
}
|
||||
|
||||
[data-mode='dark'] & {
|
||||
color: $lbry-white;
|
||||
border-color: $border-color--dark;
|
||||
}
|
||||
}
|
||||
|
||||
.claim-upload__progress--outer {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.claim-upload__progress--inner {
|
||||
background: $lbry-teal-1;
|
||||
color: $lbry-gray-1;
|
||||
|
||||
[data-mode='dark'] & {
|
||||
background: $lbry-teal-4;
|
||||
color: $lbry-white;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -728,6 +728,7 @@
|
|||
"Your LBRY credits are controllable by you and only you, via a wallet file stored locally on your computer.": "Your LBRY credits are controllable by you and only you, via a wallet file stored locally on your computer.",
|
||||
"However, it is easy to back up manually. To backup your wallet, make a copy of the folder listed below:": "However, it is easy to back up manually. To backup your wallet, make a copy of the folder listed below:",
|
||||
"Access to these files are equivalent to having access to your credits. Keep any copies you make of your wallet in a secure place. For more details on backing up and best practices %helpLink%.": "Access to these files are equivalent to having access to your credits. Keep any copies you make of your wallet in a secure place. For more details on backing up and best practices %helpLink%.",
|
||||
}
|
||||
"Your Channels": "Your Channels",
|
||||
"Add Tags": "Add Tags",
|
||||
"Available Balance": "Available Balance",
|
||||
|
|
Loading…
Reference in a new issue