Merge branch 'master' of https://github.com/amitnndn/lbry-app
This commit is contained in:
commit
5ffc3ab52c
104 changed files with 1516 additions and 2021 deletions
|
@ -35,6 +35,9 @@
|
||||||
}],
|
}],
|
||||||
"func-names": ["warn", "as-needed"],
|
"func-names": ["warn", "as-needed"],
|
||||||
"jsx-a11y/label-has-for": 0,
|
"jsx-a11y/label-has-for": 0,
|
||||||
"import/prefer-default-export": 0
|
"import/prefer-default-export": 0,
|
||||||
|
"no-return-assign": 0,
|
||||||
|
"react/require-default-props": 0,
|
||||||
|
"react/jsx-closing-tag-location": 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
6
.idea/inspectionProfiles/Project_Default.xml
generated
6
.idea/inspectionProfiles/Project_Default.xml
generated
|
@ -1,6 +0,0 @@
|
||||||
<component name="InspectionProjectProfileManager">
|
|
||||||
<profile version="1.0">
|
|
||||||
<option name="myName" value="Project Default" />
|
|
||||||
<inspection_tool class="Eslint" enabled="true" level="ERROR" enabled_by_default="true" />
|
|
||||||
</profile>
|
|
||||||
</component>
|
|
12
.idea/lbry-app.iml
generated
12
.idea/lbry-app.iml
generated
|
@ -1,12 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<module type="WEB_MODULE" version="4">
|
|
||||||
<component name="NewModuleRootManager">
|
|
||||||
<content url="file://$MODULE_DIR$">
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/.tmp" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/temp" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/tmp" />
|
|
||||||
</content>
|
|
||||||
<orderEntry type="inheritedJdk" />
|
|
||||||
<orderEntry type="sourceFolder" forTests="false" />
|
|
||||||
</component>
|
|
||||||
</module>
|
|
6
.idea/misc.xml
generated
6
.idea/misc.xml
generated
|
@ -1,6 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="JavaScriptSettings">
|
|
||||||
<option name="languageLevel" value="FLOW" />
|
|
||||||
</component>
|
|
||||||
</project>
|
|
8
.idea/modules.xml
generated
8
.idea/modules.xml
generated
|
@ -1,8 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="ProjectModuleManager">
|
|
||||||
<modules>
|
|
||||||
<module fileurl="file://$PROJECT_DIR$/.idea/lbry-app.iml" filepath="$PROJECT_DIR$/.idea/lbry-app.iml" />
|
|
||||||
</modules>
|
|
||||||
</component>
|
|
||||||
</project>
|
|
6
.idea/vcs.xml
generated
6
.idea/vcs.xml
generated
|
@ -1,6 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="VcsDirectoryMappings">
|
|
||||||
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
|
||||||
</component>
|
|
||||||
</project>
|
|
547
.idea/workspace.xml
generated
547
.idea/workspace.xml
generated
|
@ -1,547 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="ChangeListManager">
|
|
||||||
<list default="true" id="061e089e-71dc-4d6b-b27c-9c614b097257" name="Default" comment="">
|
|
||||||
<change type="NEW" beforePath="" afterPath="$PROJECT_DIR$/src/renderer/types/claim.js" />
|
|
||||||
<change type="MODIFICATION" beforePath="$PROJECT_DIR$/src/renderer/component/fileDetails/view.jsx" afterPath="$PROJECT_DIR$/src/renderer/component/fileDetails/view.jsx" />
|
|
||||||
<change type="MODIFICATION" beforePath="$PROJECT_DIR$/src/renderer/component/uriIndicator/view.jsx" afterPath="$PROJECT_DIR$/src/renderer/component/uriIndicator/view.jsx" />
|
|
||||||
<change type="MODIFICATION" beforePath="$PROJECT_DIR$/src/renderer/component/video/view.jsx" afterPath="$PROJECT_DIR$/src/renderer/component/video/view.jsx" />
|
|
||||||
<change type="MODIFICATION" beforePath="$PROJECT_DIR$/src/renderer/component/walletSendTip/view.jsx" afterPath="$PROJECT_DIR$/src/renderer/component/walletSendTip/view.jsx" />
|
|
||||||
<change type="MODIFICATION" beforePath="$PROJECT_DIR$/src/renderer/page/channel/view.jsx" afterPath="$PROJECT_DIR$/src/renderer/page/channel/view.jsx" />
|
|
||||||
<change type="MODIFICATION" beforePath="$PROJECT_DIR$/src/renderer/page/file/view.jsx" afterPath="$PROJECT_DIR$/src/renderer/page/file/view.jsx" />
|
|
||||||
<change type="MODIFICATION" beforePath="$PROJECT_DIR$/src/renderer/page/show/view.jsx" afterPath="$PROJECT_DIR$/src/renderer/page/show/view.jsx" />
|
|
||||||
<change type="MODIFICATION" beforePath="$PROJECT_DIR$/src/renderer/page/subscriptions/view.jsx" afterPath="$PROJECT_DIR$/src/renderer/page/subscriptions/view.jsx" />
|
|
||||||
</list>
|
|
||||||
<ignored path="$PROJECT_DIR$/.tmp/" />
|
|
||||||
<ignored path="$PROJECT_DIR$/temp/" />
|
|
||||||
<ignored path="$PROJECT_DIR$/tmp/" />
|
|
||||||
<option name="EXCLUDED_CONVERTED_TO_IGNORED" value="true" />
|
|
||||||
<option name="TRACKING_ENABLED" value="true" />
|
|
||||||
<option name="SHOW_DIALOG" value="false" />
|
|
||||||
<option name="HIGHLIGHT_CONFLICTS" value="true" />
|
|
||||||
<option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
|
|
||||||
<option name="LAST_RESOLUTION" value="IGNORE" />
|
|
||||||
</component>
|
|
||||||
<component name="FileEditorManager">
|
|
||||||
<leaf SIDE_TABS_SIZE_LIMIT_KEY="300">
|
|
||||||
<file leaf-file-name="view.jsx" pinned="false" current-in-tab="false">
|
|
||||||
<entry file="file://$PROJECT_DIR$/src/renderer/modal/modalRouter/view.jsx">
|
|
||||||
<provider selected="true" editor-type-id="text-editor">
|
|
||||||
<state relative-caret-position="0">
|
|
||||||
<caret line="0" column="0" lean-forward="false" selection-start-line="0" selection-start-column="0" selection-end-line="0" selection-end-column="0" />
|
|
||||||
<folding>
|
|
||||||
<element signature="e#0#26#0" expanded="true" />
|
|
||||||
<marker date="1526068149928" expanded="true" signature="5366:5471" ph="{...}" />
|
|
||||||
</folding>
|
|
||||||
</state>
|
|
||||||
</provider>
|
|
||||||
</entry>
|
|
||||||
</file>
|
|
||||||
<file leaf-file-name="index.js" pinned="false" current-in-tab="false">
|
|
||||||
<entry file="file://$PROJECT_DIR$/src/renderer/modal/modalRouter/index.js">
|
|
||||||
<provider selected="true" editor-type-id="text-editor">
|
|
||||||
<state relative-caret-position="216">
|
|
||||||
<caret line="12" column="0" lean-forward="false" selection-start-line="12" selection-start-column="0" selection-end-line="12" selection-end-column="0" />
|
|
||||||
<folding>
|
|
||||||
<marker date="1525123536618" expanded="true" signature="1172:1177" ph="{...}" />
|
|
||||||
</folding>
|
|
||||||
</state>
|
|
||||||
</provider>
|
|
||||||
</entry>
|
|
||||||
</file>
|
|
||||||
<file leaf-file-name="package.json" pinned="false" current-in-tab="false">
|
|
||||||
<entry file="file://$PROJECT_DIR$/package.json">
|
|
||||||
<provider selected="true" editor-type-id="text-editor">
|
|
||||||
<state relative-caret-position="1332">
|
|
||||||
<caret line="74" column="0" lean-forward="false" selection-start-line="74" selection-start-column="0" selection-end-line="74" selection-end-column="0" />
|
|
||||||
<folding>
|
|
||||||
<marker date="1526397284183" expanded="true" signature="2668:3140" ph="{"axios": "^0.18.0"...}" />
|
|
||||||
</folding>
|
|
||||||
</state>
|
|
||||||
</provider>
|
|
||||||
</entry>
|
|
||||||
</file>
|
|
||||||
<file leaf-file-name="join.js" pinned="false" current-in-tab="false">
|
|
||||||
<entry file="file://$PROJECT_DIR$/node_modules/bluebird/js/release/join.js">
|
|
||||||
<provider selected="true" editor-type-id="text-editor">
|
|
||||||
<state relative-caret-position="144">
|
|
||||||
<caret line="8" column="11" lean-forward="false" selection-start-line="8" selection-start-column="11" selection-end-line="8" selection-end-column="11" />
|
|
||||||
<folding />
|
|
||||||
</state>
|
|
||||||
</provider>
|
|
||||||
</entry>
|
|
||||||
</file>
|
|
||||||
<file leaf-file-name="view.jsx" pinned="false" current-in-tab="true">
|
|
||||||
<entry file="file://$PROJECT_DIR$/src/renderer/page/file/view.jsx">
|
|
||||||
<provider selected="true" editor-type-id="text-editor">
|
|
||||||
<state relative-caret-position="287">
|
|
||||||
<caret line="18" column="15" lean-forward="false" selection-start-line="18" selection-start-column="14" selection-end-line="18" selection-end-column="15" />
|
|
||||||
<folding />
|
|
||||||
</state>
|
|
||||||
</provider>
|
|
||||||
</entry>
|
|
||||||
</file>
|
|
||||||
</leaf>
|
|
||||||
</component>
|
|
||||||
<component name="FindInProjectRecents">
|
|
||||||
<findStrings>
|
|
||||||
<find>TYPE_FEATURED_DOWNLOAD</find>
|
|
||||||
<find>TYPE_FEATURED_DOW</find>
|
|
||||||
<find>doOpen</find>
|
|
||||||
<find>doNotify</find>
|
|
||||||
<find>settings</find>
|
|
||||||
</findStrings>
|
|
||||||
</component>
|
|
||||||
<component name="Git.Settings">
|
|
||||||
<option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$" />
|
|
||||||
</component>
|
|
||||||
<component name="IdeDocumentHistory">
|
|
||||||
<option name="CHANGED_PATHS">
|
|
||||||
<list>
|
|
||||||
<option value="$PROJECT_DIR$/src/renderer/modal/modalRouter/index.js" />
|
|
||||||
<option value="$PROJECT_DIR$/package.json" />
|
|
||||||
<option value="$PROJECT_DIR$/README.md" />
|
|
||||||
<option value="$PROJECT_DIR$/src/renderer/page/file/view.jsx" />
|
|
||||||
</list>
|
|
||||||
</option>
|
|
||||||
</component>
|
|
||||||
<component name="JsBuildToolGruntFileManager" detection-done="true" sorting="DEFINITION_ORDER" />
|
|
||||||
<component name="JsBuildToolPackageJson" detection-done="true" sorting="DEFINITION_ORDER">
|
|
||||||
<package-json value="$PROJECT_DIR$/package.json" />
|
|
||||||
</component>
|
|
||||||
<component name="JsFlowSettings">
|
|
||||||
<service-enabled>true</service-enabled>
|
|
||||||
<exe-path />
|
|
||||||
<annotation-enable>false</annotation-enable>
|
|
||||||
<other-services-enabled>true</other-services-enabled>
|
|
||||||
<auto-save>true</auto-save>
|
|
||||||
</component>
|
|
||||||
<component name="JsGulpfileManager">
|
|
||||||
<detection-done>true</detection-done>
|
|
||||||
<sorting>DEFINITION_ORDER</sorting>
|
|
||||||
</component>
|
|
||||||
<component name="NodeModulesDirectoryManager">
|
|
||||||
<handled-path value="$PROJECT_DIR$/dist/linux-unpacked/resources/app.asar.unpacked/node_modules" />
|
|
||||||
<handled-path value="$PROJECT_DIR$/node_modules" />
|
|
||||||
</component>
|
|
||||||
<component name="PhpWorkspaceProjectConfiguration" backward_compatibility_performed="true" />
|
|
||||||
<component name="ProjectFrameBounds" extendedState="6">
|
|
||||||
<option name="y" value="24" />
|
|
||||||
<option name="width" value="1920" />
|
|
||||||
<option name="height" value="1056" />
|
|
||||||
</component>
|
|
||||||
<component name="ProjectLevelVcsManager" settingsEditedManually="true" />
|
|
||||||
<component name="ProjectView">
|
|
||||||
<navigator currentView="ProjectPane" proportions="" version="1">
|
|
||||||
<flattenPackages />
|
|
||||||
<showMembers />
|
|
||||||
<showModules />
|
|
||||||
<showLibraryContents />
|
|
||||||
<hideEmptyPackages />
|
|
||||||
<abbreviatePackageNames />
|
|
||||||
<autoscrollToSource />
|
|
||||||
<autoscrollFromSource />
|
|
||||||
<sortByType />
|
|
||||||
<manualOrder />
|
|
||||||
<foldersAlwaysOnTop value="true" />
|
|
||||||
</navigator>
|
|
||||||
<panes>
|
|
||||||
<pane id="Scope" />
|
|
||||||
<pane id="ProjectPane">
|
|
||||||
<subPane>
|
|
||||||
<expand>
|
|
||||||
<path>
|
|
||||||
<item name="lbry-app" type="b2602c69:ProjectViewProjectNode" />
|
|
||||||
<item name="lbry-app" type="2a2b976b:PhpTreeStructureProvider$1" />
|
|
||||||
</path>
|
|
||||||
</expand>
|
|
||||||
<select />
|
|
||||||
</subPane>
|
|
||||||
</pane>
|
|
||||||
<pane id="Scratches" />
|
|
||||||
</panes>
|
|
||||||
</component>
|
|
||||||
<component name="PropertiesComponent">
|
|
||||||
<property name="WebServerToolWindowFactoryState" value="false" />
|
|
||||||
<property name="nodejs_interpreter_path" value="/usr/local/bin/node" />
|
|
||||||
<property name="HbShouldOpenHtmlAsHb" value="" />
|
|
||||||
<property name="node.js.path.for.package.eslint" value="project" />
|
|
||||||
<property name="node.js.detected.package.eslint" value="true" />
|
|
||||||
<property name="node.js.selected.package.eslint" value="$PROJECT_DIR$/node_modules/eslint" />
|
|
||||||
<property name="last_opened_file_path" value="$PROJECT_DIR$" />
|
|
||||||
</component>
|
|
||||||
<component name="RunDashboard">
|
|
||||||
<option name="ruleStates">
|
|
||||||
<list>
|
|
||||||
<RuleState>
|
|
||||||
<option name="name" value="ConfigurationTypeDashboardGroupingRule" />
|
|
||||||
</RuleState>
|
|
||||||
<RuleState>
|
|
||||||
<option name="name" value="StatusDashboardGroupingRule" />
|
|
||||||
</RuleState>
|
|
||||||
</list>
|
|
||||||
</option>
|
|
||||||
</component>
|
|
||||||
<component name="ShelveChangesManager" show_recycled="false">
|
|
||||||
<option name="remove_strategy" value="false" />
|
|
||||||
</component>
|
|
||||||
<component name="SvnConfiguration">
|
|
||||||
<configuration />
|
|
||||||
</component>
|
|
||||||
<component name="TaskManager">
|
|
||||||
<task active="true" id="Default" summary="Default task">
|
|
||||||
<changelist id="061e089e-71dc-4d6b-b27c-9c614b097257" name="Default" comment="" />
|
|
||||||
<created>1522354295512</created>
|
|
||||||
<option name="number" value="Default" />
|
|
||||||
<option name="presentableId" value="Default" />
|
|
||||||
<updated>1522354295512</updated>
|
|
||||||
<workItem from="1522354299246" duration="1866000" />
|
|
||||||
<workItem from="1522643117648" duration="2000" />
|
|
||||||
<workItem from="1524064618567" duration="2674000" />
|
|
||||||
<workItem from="1525381677126" duration="197000" />
|
|
||||||
<workItem from="1525382363305" duration="597000" />
|
|
||||||
<workItem from="1525461458836" duration="70000" />
|
|
||||||
<workItem from="1526067492327" duration="897000" />
|
|
||||||
<workItem from="1526397339713" duration="27000" />
|
|
||||||
</task>
|
|
||||||
<servers />
|
|
||||||
</component>
|
|
||||||
<component name="TimeTrackingManager">
|
|
||||||
<option name="totallyTimeSpent" value="6330000" />
|
|
||||||
</component>
|
|
||||||
<component name="ToolWindowManager">
|
|
||||||
<frame x="0" y="24" width="1920" height="1055" extended-state="6" />
|
|
||||||
<editor active="true" />
|
|
||||||
<layout>
|
|
||||||
<window_info id="Project" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="true" show_stripe_button="true" weight="0.25" sideWeight="0.5" order="0" side_tool="false" content_ui="combo" />
|
|
||||||
<window_info id="TODO" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="6" side_tool="false" content_ui="tabs" />
|
|
||||||
<window_info id="Event Log" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="7" side_tool="true" content_ui="tabs" />
|
|
||||||
<window_info id="Version Control" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="7" side_tool="false" content_ui="tabs" />
|
|
||||||
<window_info id="npm" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="2" side_tool="true" content_ui="tabs" />
|
|
||||||
<window_info id="Run" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="2" side_tool="false" content_ui="tabs" />
|
|
||||||
<window_info id="Structure" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.25" sideWeight="0.5" order="1" side_tool="false" content_ui="tabs" />
|
|
||||||
<window_info id="Terminal" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="7" side_tool="false" content_ui="tabs" />
|
|
||||||
<window_info id="Favorites" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="2" side_tool="true" content_ui="tabs" />
|
|
||||||
<window_info id="Debug" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.4" sideWeight="0.5" order="3" side_tool="false" content_ui="tabs" />
|
|
||||||
<window_info id="Cvs" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.25" sideWeight="0.5" order="4" side_tool="false" content_ui="tabs" />
|
|
||||||
<window_info id="Message" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="0" side_tool="false" content_ui="tabs" />
|
|
||||||
<window_info id="Commander" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.4" sideWeight="0.5" order="0" side_tool="false" content_ui="tabs" />
|
|
||||||
<window_info id="Inspection" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.4" sideWeight="0.5" order="5" side_tool="false" content_ui="tabs" />
|
|
||||||
<window_info id="Hierarchy" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.25" sideWeight="0.5" order="2" side_tool="false" content_ui="combo" />
|
|
||||||
<window_info id="Find" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="1" side_tool="false" content_ui="tabs" />
|
|
||||||
<window_info id="Database" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="3" side_tool="false" content_ui="tabs" />
|
|
||||||
<window_info id="Ant Build" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.25" sideWeight="0.5" order="1" side_tool="false" content_ui="tabs" />
|
|
||||||
</layout>
|
|
||||||
</component>
|
|
||||||
<component name="TypeScriptGeneratedFilesManager">
|
|
||||||
<option name="version" value="1" />
|
|
||||||
</component>
|
|
||||||
<component name="VcsContentAnnotationSettings">
|
|
||||||
<option name="myLimit" value="2678400000" />
|
|
||||||
</component>
|
|
||||||
<component name="XDebuggerManager">
|
|
||||||
<breakpoint-manager />
|
|
||||||
<watches-manager />
|
|
||||||
</component>
|
|
||||||
<component name="editorHistoryManager">
|
|
||||||
<entry file="file://$PROJECT_DIR$/src/renderer/modal/modalRouter/view.jsx">
|
|
||||||
<provider selected="true" editor-type-id="text-editor">
|
|
||||||
<state relative-caret-position="0">
|
|
||||||
<caret line="0" column="0" lean-forward="false" selection-start-line="0" selection-start-column="0" selection-end-line="0" selection-end-column="0" />
|
|
||||||
<folding>
|
|
||||||
<element signature="e#0#26#0" expanded="true" />
|
|
||||||
<marker date="1526068149928" expanded="true" signature="5366:5471" ph="{...}" />
|
|
||||||
</folding>
|
|
||||||
</state>
|
|
||||||
</provider>
|
|
||||||
</entry>
|
|
||||||
<entry file="file://$PROJECT_DIR$/src/renderer/modal/modalRouter/index.js">
|
|
||||||
<provider selected="true" editor-type-id="text-editor">
|
|
||||||
<state relative-caret-position="216">
|
|
||||||
<caret line="12" column="0" lean-forward="false" selection-start-line="12" selection-start-column="0" selection-end-line="12" selection-end-column="0" />
|
|
||||||
<folding>
|
|
||||||
<marker date="1525123536618" expanded="true" signature="1172:1177" ph="{...}" />
|
|
||||||
</folding>
|
|
||||||
</state>
|
|
||||||
</provider>
|
|
||||||
</entry>
|
|
||||||
<entry file="file://$PROJECT_DIR$/package.json">
|
|
||||||
<provider selected="true" editor-type-id="text-editor">
|
|
||||||
<state relative-caret-position="1332">
|
|
||||||
<caret line="74" column="0" lean-forward="false" selection-start-line="74" selection-start-column="0" selection-end-line="74" selection-end-column="0" />
|
|
||||||
<folding>
|
|
||||||
<marker date="1526397284183" expanded="true" signature="2668:3140" ph="{"axios": "^0.18.0"...}" />
|
|
||||||
</folding>
|
|
||||||
</state>
|
|
||||||
</provider>
|
|
||||||
</entry>
|
|
||||||
<entry file="file://$PROJECT_DIR$/node_modules/bluebird/js/release/join.js">
|
|
||||||
<provider selected="true" editor-type-id="text-editor">
|
|
||||||
<state relative-caret-position="144">
|
|
||||||
<caret line="8" column="11" lean-forward="false" selection-start-line="8" selection-start-column="11" selection-end-line="8" selection-end-column="11" />
|
|
||||||
<folding />
|
|
||||||
</state>
|
|
||||||
</provider>
|
|
||||||
</entry>
|
|
||||||
<entry file="file://$PROJECT_DIR$/src/renderer/modal/modalRouter/view.jsx">
|
|
||||||
<provider selected="true" editor-type-id="text-editor">
|
|
||||||
<state relative-caret-position="0">
|
|
||||||
<caret line="0" column="0" lean-forward="false" selection-start-line="0" selection-start-column="0" selection-end-line="0" selection-end-column="0" />
|
|
||||||
<folding>
|
|
||||||
<element signature="e#0#26#0" expanded="true" />
|
|
||||||
<marker date="1526068149928" expanded="true" signature="5366:5471" ph="{...}" />
|
|
||||||
</folding>
|
|
||||||
</state>
|
|
||||||
</provider>
|
|
||||||
</entry>
|
|
||||||
<entry file="file://$PROJECT_DIR$/package.json">
|
|
||||||
<provider selected="true" editor-type-id="text-editor">
|
|
||||||
<state relative-caret-position="1332">
|
|
||||||
<caret line="74" column="0" lean-forward="false" selection-start-line="74" selection-start-column="0" selection-end-line="74" selection-end-column="0" />
|
|
||||||
<folding>
|
|
||||||
<marker date="1526397284183" expanded="true" signature="2668:3140" ph="{"axios": "^0.18.0"...}" />
|
|
||||||
</folding>
|
|
||||||
</state>
|
|
||||||
</provider>
|
|
||||||
</entry>
|
|
||||||
<entry file="file://$PROJECT_DIR$/src/renderer/modal/modalRouter/index.js">
|
|
||||||
<provider selected="true" editor-type-id="text-editor">
|
|
||||||
<state relative-caret-position="216">
|
|
||||||
<caret line="12" column="0" lean-forward="false" selection-start-line="12" selection-start-column="0" selection-end-line="12" selection-end-column="0" />
|
|
||||||
<folding>
|
|
||||||
<marker date="1525123536618" expanded="true" signature="1172:1177" ph="{...}" />
|
|
||||||
</folding>
|
|
||||||
</state>
|
|
||||||
</provider>
|
|
||||||
</entry>
|
|
||||||
<entry file="file://$PROJECT_DIR$/node_modules/bluebird/js/release/join.js">
|
|
||||||
<provider selected="true" editor-type-id="text-editor">
|
|
||||||
<state relative-caret-position="0">
|
|
||||||
<caret line="0" column="0" lean-forward="false" selection-start-line="0" selection-start-column="0" selection-end-line="0" selection-end-column="0" />
|
|
||||||
<folding />
|
|
||||||
</state>
|
|
||||||
</provider>
|
|
||||||
</entry>
|
|
||||||
<entry file="file://$PROJECT_DIR$/src/renderer/modal/modalRouter/view.jsx">
|
|
||||||
<provider selected="true" editor-type-id="text-editor">
|
|
||||||
<state relative-caret-position="0">
|
|
||||||
<caret line="0" column="0" lean-forward="false" selection-start-line="0" selection-start-column="0" selection-end-line="0" selection-end-column="0" />
|
|
||||||
<folding>
|
|
||||||
<element signature="e#0#26#0" expanded="true" />
|
|
||||||
<marker date="1526068149928" expanded="true" signature="5366:5471" ph="{...}" />
|
|
||||||
</folding>
|
|
||||||
</state>
|
|
||||||
</provider>
|
|
||||||
</entry>
|
|
||||||
<entry file="file://$PROJECT_DIR$/src/renderer/modal/modalRouter/index.js">
|
|
||||||
<provider selected="true" editor-type-id="text-editor">
|
|
||||||
<state relative-caret-position="216">
|
|
||||||
<caret line="12" column="0" lean-forward="false" selection-start-line="12" selection-start-column="0" selection-end-line="12" selection-end-column="0" />
|
|
||||||
<folding>
|
|
||||||
<marker date="1525123536618" expanded="true" signature="1172:1177" ph="{...}" />
|
|
||||||
</folding>
|
|
||||||
</state>
|
|
||||||
</provider>
|
|
||||||
</entry>
|
|
||||||
<entry file="file://$PROJECT_DIR$/package.json">
|
|
||||||
<provider selected="true" editor-type-id="text-editor">
|
|
||||||
<state relative-caret-position="2322">
|
|
||||||
<caret line="129" column="38" lean-forward="false" selection-start-line="129" selection-start-column="38" selection-end-line="129" selection-end-column="38" />
|
|
||||||
<folding>
|
|
||||||
<marker date="1526397284183" expanded="true" signature="2668:3140" ph="{"axios": "^0.18.0"...}" />
|
|
||||||
</folding>
|
|
||||||
</state>
|
|
||||||
</provider>
|
|
||||||
</entry>
|
|
||||||
<entry file="file://$PROJECT_DIR$/src/renderer/modal/modalRouter/view.jsx">
|
|
||||||
<provider selected="true" editor-type-id="text-editor">
|
|
||||||
<state relative-caret-position="0">
|
|
||||||
<caret line="0" column="0" lean-forward="false" selection-start-line="0" selection-start-column="0" selection-end-line="0" selection-end-column="0" />
|
|
||||||
<folding>
|
|
||||||
<element signature="e#0#26#0" expanded="true" />
|
|
||||||
<marker date="1526068149928" expanded="true" signature="5366:5471" ph="{...}" />
|
|
||||||
</folding>
|
|
||||||
</state>
|
|
||||||
</provider>
|
|
||||||
</entry>
|
|
||||||
<entry file="file://$PROJECT_DIR$/src/renderer/modal/modalRouter/index.js">
|
|
||||||
<provider selected="true" editor-type-id="text-editor">
|
|
||||||
<state relative-caret-position="144">
|
|
||||||
<caret line="19" column="68" lean-forward="true" selection-start-line="19" selection-start-column="68" selection-end-line="19" selection-end-column="68" />
|
|
||||||
<folding>
|
|
||||||
<marker date="1525123536618" expanded="true" signature="1172:1177" ph="{...}" />
|
|
||||||
</folding>
|
|
||||||
</state>
|
|
||||||
</provider>
|
|
||||||
</entry>
|
|
||||||
<entry file="file://$PROJECT_DIR$/src/renderer/page/rewards/view.jsx">
|
|
||||||
<provider selected="true" editor-type-id="text-editor">
|
|
||||||
<state relative-caret-position="-122">
|
|
||||||
<caret line="0" column="0" lean-forward="false" selection-start-line="0" selection-start-column="0" selection-end-line="0" selection-end-column="0" />
|
|
||||||
</state>
|
|
||||||
</provider>
|
|
||||||
</entry>
|
|
||||||
<entry file="file://$PROJECT_DIR$/src/renderer/redux/reducers/rewards.js">
|
|
||||||
<provider selected="true" editor-type-id="text-editor">
|
|
||||||
<state relative-caret-position="-28">
|
|
||||||
<caret line="0" column="0" lean-forward="false" selection-start-line="0" selection-start-column="0" selection-end-line="0" selection-end-column="0" />
|
|
||||||
</state>
|
|
||||||
</provider>
|
|
||||||
</entry>
|
|
||||||
<entry file="file://$PROJECT_DIR$/src/renderer/redux/actions/rewards.js">
|
|
||||||
<provider selected="true" editor-type-id="text-editor">
|
|
||||||
<state relative-caret-position="-832">
|
|
||||||
<caret line="13" column="61" lean-forward="false" selection-start-line="13" selection-start-column="36" selection-end-line="13" selection-end-column="61" />
|
|
||||||
</state>
|
|
||||||
</provider>
|
|
||||||
</entry>
|
|
||||||
<entry file="file://$PROJECT_DIR$/src/renderer/rewards.js">
|
|
||||||
<provider selected="true" editor-type-id="text-editor">
|
|
||||||
<state relative-caret-position="324">
|
|
||||||
<caret line="18" column="0" lean-forward="false" selection-start-line="18" selection-start-column="0" selection-end-line="18" selection-end-column="0" />
|
|
||||||
</state>
|
|
||||||
</provider>
|
|
||||||
</entry>
|
|
||||||
<entry file="file://$PROJECT_DIR$/src/renderer/modal/modalRouter/view.jsx">
|
|
||||||
<provider selected="true" editor-type-id="text-editor">
|
|
||||||
<state relative-caret-position="0">
|
|
||||||
<caret line="0" column="0" lean-forward="false" selection-start-line="0" selection-start-column="0" selection-end-line="0" selection-end-column="0" />
|
|
||||||
<folding>
|
|
||||||
<element signature="e#0#26#0" expanded="true" />
|
|
||||||
<marker date="1526068149928" expanded="true" signature="5366:5471" ph="{...}" />
|
|
||||||
</folding>
|
|
||||||
</state>
|
|
||||||
</provider>
|
|
||||||
</entry>
|
|
||||||
<entry file="file://$PROJECT_DIR$/src/renderer/modal/modalRouter/index.js">
|
|
||||||
<provider selected="true" editor-type-id="text-editor">
|
|
||||||
<state relative-caret-position="216">
|
|
||||||
<caret line="12" column="0" lean-forward="false" selection-start-line="12" selection-start-column="0" selection-end-line="12" selection-end-column="0" />
|
|
||||||
<folding>
|
|
||||||
<marker date="1525123536618" expanded="true" signature="1172:1177" ph="{...}" />
|
|
||||||
</folding>
|
|
||||||
</state>
|
|
||||||
</provider>
|
|
||||||
</entry>
|
|
||||||
<entry file="file://$PROJECT_DIR$/package.json">
|
|
||||||
<provider selected="true" editor-type-id="text-editor">
|
|
||||||
<state relative-caret-position="693">
|
|
||||||
<caret line="129" column="38" lean-forward="false" selection-start-line="129" selection-start-column="38" selection-end-line="129" selection-end-column="38" />
|
|
||||||
<folding>
|
|
||||||
<marker date="1526397284183" expanded="true" signature="2668:3140" ph="{"axios": "^0.18.0"...}" />
|
|
||||||
</folding>
|
|
||||||
</state>
|
|
||||||
</provider>
|
|
||||||
</entry>
|
|
||||||
<entry file="file://$PROJECT_DIR$/src/renderer/modal/modalRouter/view.jsx">
|
|
||||||
<provider selected="true" editor-type-id="text-editor">
|
|
||||||
<state relative-caret-position="0">
|
|
||||||
<caret line="0" column="0" lean-forward="false" selection-start-line="0" selection-start-column="0" selection-end-line="0" selection-end-column="0" />
|
|
||||||
<folding>
|
|
||||||
<element signature="e#0#26#0" expanded="true" />
|
|
||||||
<marker date="1526068149928" expanded="true" signature="5366:5471" ph="{...}" />
|
|
||||||
</folding>
|
|
||||||
</state>
|
|
||||||
</provider>
|
|
||||||
</entry>
|
|
||||||
<entry file="file://$PROJECT_DIR$/src/renderer/modal/modalRouter/index.js">
|
|
||||||
<provider selected="true" editor-type-id="text-editor">
|
|
||||||
<state relative-caret-position="144">
|
|
||||||
<caret line="19" column="68" lean-forward="true" selection-start-line="19" selection-start-column="68" selection-end-line="19" selection-end-column="68" />
|
|
||||||
<folding>
|
|
||||||
<marker date="1525123536618" expanded="true" signature="1172:1177" ph="{...}" />
|
|
||||||
</folding>
|
|
||||||
</state>
|
|
||||||
</provider>
|
|
||||||
</entry>
|
|
||||||
<entry file="file://$PROJECT_DIR$/src/renderer/page/rewards/view.jsx">
|
|
||||||
<provider selected="true" editor-type-id="text-editor">
|
|
||||||
<state relative-caret-position="-122">
|
|
||||||
<caret line="0" column="0" lean-forward="false" selection-start-line="0" selection-start-column="0" selection-end-line="0" selection-end-column="0" />
|
|
||||||
</state>
|
|
||||||
</provider>
|
|
||||||
</entry>
|
|
||||||
<entry file="file://$PROJECT_DIR$/src/renderer/redux/reducers/rewards.js">
|
|
||||||
<provider selected="true" editor-type-id="text-editor">
|
|
||||||
<state relative-caret-position="-28">
|
|
||||||
<caret line="0" column="0" lean-forward="false" selection-start-line="0" selection-start-column="0" selection-end-line="0" selection-end-column="0" />
|
|
||||||
</state>
|
|
||||||
</provider>
|
|
||||||
</entry>
|
|
||||||
<entry file="file://$PROJECT_DIR$/src/renderer/redux/actions/rewards.js">
|
|
||||||
<provider selected="true" editor-type-id="text-editor">
|
|
||||||
<state relative-caret-position="-832">
|
|
||||||
<caret line="13" column="61" lean-forward="false" selection-start-line="13" selection-start-column="36" selection-end-line="13" selection-end-column="61" />
|
|
||||||
</state>
|
|
||||||
</provider>
|
|
||||||
</entry>
|
|
||||||
<entry file="file://$PROJECT_DIR$/src/renderer/rewards.js">
|
|
||||||
<provider selected="true" editor-type-id="text-editor">
|
|
||||||
<state relative-caret-position="324">
|
|
||||||
<caret line="18" column="0" lean-forward="false" selection-start-line="18" selection-start-column="0" selection-end-line="18" selection-end-column="0" />
|
|
||||||
</state>
|
|
||||||
</provider>
|
|
||||||
</entry>
|
|
||||||
<entry file="file://$PROJECT_DIR$/src/renderer/modal/modalRouter/view.jsx">
|
|
||||||
<provider selected="true" editor-type-id="text-editor">
|
|
||||||
<state relative-caret-position="0">
|
|
||||||
<caret line="0" column="0" lean-forward="false" selection-start-line="0" selection-start-column="0" selection-end-line="0" selection-end-column="0" />
|
|
||||||
<folding>
|
|
||||||
<element signature="e#0#26#0" expanded="true" />
|
|
||||||
<marker date="1526068149928" expanded="true" signature="5366:5471" ph="{...}" />
|
|
||||||
</folding>
|
|
||||||
</state>
|
|
||||||
</provider>
|
|
||||||
</entry>
|
|
||||||
<entry file="file://$PROJECT_DIR$/src/renderer/modal/modalRouter/index.js">
|
|
||||||
<provider selected="true" editor-type-id="text-editor">
|
|
||||||
<state relative-caret-position="216">
|
|
||||||
<caret line="12" column="0" lean-forward="false" selection-start-line="12" selection-start-column="0" selection-end-line="12" selection-end-column="0" />
|
|
||||||
<folding>
|
|
||||||
<marker date="1525123536618" expanded="true" signature="1172:1177" ph="{...}" />
|
|
||||||
</folding>
|
|
||||||
</state>
|
|
||||||
</provider>
|
|
||||||
</entry>
|
|
||||||
<entry file="file://$PROJECT_DIR$/package.json">
|
|
||||||
<provider selected="true" editor-type-id="text-editor">
|
|
||||||
<state relative-caret-position="1332">
|
|
||||||
<caret line="74" column="0" lean-forward="false" selection-start-line="74" selection-start-column="0" selection-end-line="74" selection-end-column="0" />
|
|
||||||
<folding>
|
|
||||||
<marker date="1526397284183" expanded="true" signature="2668:3140" ph="{"axios": "^0.18.0"...}" />
|
|
||||||
</folding>
|
|
||||||
</state>
|
|
||||||
</provider>
|
|
||||||
</entry>
|
|
||||||
<entry file="file://$PROJECT_DIR$/CONTRIBUTING.md">
|
|
||||||
<provider selected="true" editor-type-id="text-editor">
|
|
||||||
<state relative-caret-position="540">
|
|
||||||
<caret line="168" column="0" lean-forward="true" selection-start-line="168" selection-start-column="0" selection-end-line="168" selection-end-column="0" />
|
|
||||||
</state>
|
|
||||||
</provider>
|
|
||||||
</entry>
|
|
||||||
<entry file="file://$PROJECT_DIR$/README.md">
|
|
||||||
<provider selected="true" editor-type-id="text-editor">
|
|
||||||
<state relative-caret-position="846">
|
|
||||||
<caret line="47" column="81" lean-forward="true" selection-start-line="47" selection-start-column="81" selection-end-line="47" selection-end-column="81" />
|
|
||||||
</state>
|
|
||||||
</provider>
|
|
||||||
</entry>
|
|
||||||
<entry file="file://$PROJECT_DIR$/node_modules/bluebird/js/release/join.js">
|
|
||||||
<provider selected="true" editor-type-id="text-editor">
|
|
||||||
<state relative-caret-position="144">
|
|
||||||
<caret line="8" column="11" lean-forward="false" selection-start-line="8" selection-start-column="11" selection-end-line="8" selection-end-column="11" />
|
|
||||||
<folding />
|
|
||||||
</state>
|
|
||||||
</provider>
|
|
||||||
</entry>
|
|
||||||
<entry file="file://$PROJECT_DIR$/src/renderer/page/file/view.jsx">
|
|
||||||
<provider selected="true" editor-type-id="text-editor">
|
|
||||||
<state relative-caret-position="287">
|
|
||||||
<caret line="18" column="15" lean-forward="false" selection-start-line="18" selection-start-column="14" selection-end-line="18" selection-end-column="15" />
|
|
||||||
<folding />
|
|
||||||
</state>
|
|
||||||
</provider>
|
|
||||||
</entry>
|
|
||||||
</component>
|
|
||||||
</project>
|
|
20
.travis.yml
20
.travis.yml
|
@ -1,16 +1,19 @@
|
||||||
matrix:
|
matrix:
|
||||||
include:
|
include:
|
||||||
- os: osx
|
- os: osx
|
||||||
|
env: TARGET=mac
|
||||||
osx_image: xcode9.2
|
osx_image: xcode9.2
|
||||||
language: node_js
|
language: node_js
|
||||||
node_js: "9"
|
node_js: "9"
|
||||||
env:
|
|
||||||
- ELECTRON_CACHE=$HOME/.cache/electron
|
|
||||||
- ELECTRON_BUILDER_CACHE=$HOME/.cache/electron-builder
|
|
||||||
- os: linux
|
- os: linux
|
||||||
|
env: TARGET=windows
|
||||||
services: docker
|
services: docker
|
||||||
language: node_js
|
language: node_js
|
||||||
node_js: "9"
|
node_js: "9"
|
||||||
|
- os: linux
|
||||||
|
env: TARGET=linux
|
||||||
|
language: node_js
|
||||||
|
node_js: "9"
|
||||||
cache: false
|
cache: false
|
||||||
before_install:
|
before_install:
|
||||||
- |
|
- |
|
||||||
|
@ -20,6 +23,7 @@ before_install:
|
||||||
else
|
else
|
||||||
sudo apt-get -qq update
|
sudo apt-get -qq update
|
||||||
sudo apt-get install -y libsecret-1-dev
|
sudo apt-get install -y libsecret-1-dev
|
||||||
|
sudo apt-get install --no-install-recommends -y gcc-multilib g++-multilib
|
||||||
curl -o- -L https://yarnpkg.com/install.sh | bash -s -- --version 1.6.0
|
curl -o- -L https://yarnpkg.com/install.sh | bash -s -- --version 1.6.0
|
||||||
export PATH="$HOME/.yarn/bin:$PATH"
|
export PATH="$HOME/.yarn/bin:$PATH"
|
||||||
fi
|
fi
|
||||||
|
@ -27,17 +31,15 @@ before_script:
|
||||||
- git lfs pull
|
- git lfs pull
|
||||||
script:
|
script:
|
||||||
- |
|
- |
|
||||||
if [ "$TRAVIS_OS_NAME" == "linux" ]; then
|
if [ "$TARGET" == "windows" ]; then
|
||||||
docker run --rm \
|
docker run --rm \
|
||||||
--env-file <(env | grep -iE 'DEBUG|NODE_|ELECTRON_|YARN_|NPM_|CI|CIRCLE|TRAVIS|APPVEYOR_|CSC_|GH_|GITHUB_|BT_|AWS_|STRIP|BUILD_') \
|
--env-file <(env | grep -iE 'DEBUG|NODE_|ELECTRON_|YARN_|NPM_|CI|CIRCLE|TRAVIS|APPVEYOR_|CSC_|GH_|GITHUB_|BT_|AWS_|STRIP|BUILD_') \
|
||||||
-v ${PWD}:/project \
|
-v ${PWD}:/project \
|
||||||
-v ~/.cache/electron:/root/.cache/electron \
|
|
||||||
-v ~/.cache/electron-builder:/root/.cache/electron-builder \
|
|
||||||
electronuserland/builder:wine \
|
electronuserland/builder:wine \
|
||||||
/bin/bash -c "yarn --link-duplicates --pure-lockfile && yarn build --linux --win --publish onTag"
|
/bin/bash -c "yarn --link-duplicates --pure-lockfile && yarn build --win --publish onTag";
|
||||||
else
|
|
||||||
yarn build --publish onTag
|
|
||||||
fi
|
fi
|
||||||
|
- if [ "$TARGET" == "mac" ]; then yarn build --publish onTag; fi
|
||||||
|
- if [ "$TARGET" == "linux" ]; then yarn --link-duplicates --pure-lockfile && yarn build --linux --publish onTag; fi
|
||||||
branches:
|
branches:
|
||||||
except:
|
except:
|
||||||
- "/^v\\d+\\.\\d+\\.\\d+$/"
|
- "/^v\\d+\\.\\d+\\.\\d+$/"
|
||||||
|
|
11
CHANGELOG.md
11
CHANGELOG.md
|
@ -14,11 +14,14 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/).
|
||||||
* Pre-fill publish URL after clicking "Put something here" link ([#1303](https://github.com/lbryio/lbry-app/pull/1303))
|
* Pre-fill publish URL after clicking "Put something here" link ([#1303](https://github.com/lbryio/lbry-app/pull/1303))
|
||||||
* Add Danger JS to automate code reviews ([#1289](https://github.com/lbryio/lbry-app/pull/1289))
|
* Add Danger JS to automate code reviews ([#1289](https://github.com/lbryio/lbry-app/pull/1289))
|
||||||
* Autoplay downloaded and free media ([#584](https://github.com/lbryio/lbry-app/pull/1453))
|
* Autoplay downloaded and free media ([#584](https://github.com/lbryio/lbry-app/pull/1453))
|
||||||
|
* Add 'Go to page' input on channel pagination ([#1166](https://github.com/lbryio/lbry-app/pull/1166))
|
||||||
|
* Add "View on web" button on file/channel pages with spee.ch link ([#1222](https://github.com/lbryio/lbry-app/pull/1222))
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
* Add flair to snackbar ([#1313](https://github.com/lbryio/lbry-app/pull/1313))
|
* Add flair to snackbar ([#1313](https://github.com/lbryio/lbry-app/pull/1313))
|
||||||
* Made font in price badge larger ([#1420](https://github.com/lbryio/lbry-app/pull/1420))
|
* Made font in price badge larger ([#1420](https://github.com/lbryio/lbry-app/pull/1420))
|
||||||
* Store subscriptions in internal database ([#1424](https://github.com/lbryio/lbry-app/pull/1424))
|
* Store subscriptions in internal database ([#1424](https://github.com/lbryio/lbry-app/pull/1424))
|
||||||
|
* Move rewards logic to interal api ([#1509](https://github.com/lbryio/lbry-app/pull/1509))
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
* Fix content-type not shown correctly in file description ([#863](https://github.com/lbryio/lbry-app/pull/863))
|
* Fix content-type not shown correctly in file description ([#863](https://github.com/lbryio/lbry-app/pull/863))
|
||||||
|
@ -33,7 +36,12 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/).
|
||||||
* Fix spacing in search suggestions ([#1422](https://github.com/lbryio/lbry-app/pull/1422))
|
* Fix spacing in search suggestions ([#1422](https://github.com/lbryio/lbry-app/pull/1422))
|
||||||
* Fix text/HTML files don't display correctly in-app anymore ([#1379](https://github.com/lbryio/lbry-app/issues/1379))
|
* Fix text/HTML files don't display correctly in-app anymore ([#1379](https://github.com/lbryio/lbry-app/issues/1379))
|
||||||
* Fix notification modals when reward is claimed ([#1436](https://github.com/lbryio/lbry-app/issues/1436)) and ([#1407](https://github.com/lbryio/lbry-app/issues/1407))
|
* Fix notification modals when reward is claimed ([#1436](https://github.com/lbryio/lbry-app/issues/1436)) and ([#1407](https://github.com/lbryio/lbry-app/issues/1407))
|
||||||
|
* Fix disabled cards(grayed out) ([#1466](https://github.com/lbryio/lbry-app/issues/1466))
|
||||||
* Fix markdown render ([#1179](https://github.com/lbryio/lbry-app/issues/1179))
|
* Fix markdown render ([#1179](https://github.com/lbryio/lbry-app/issues/1179))
|
||||||
|
* Fix new lines not showing correctly after markdown changes ([#1504](https://github.com/lbryio/lbry-app/issues/1504))
|
||||||
|
* Fix claim ID being null when reporting a claim that was not previously download ([issue#1512](https://github.com/lbryio/lbry-app/issues/1512)) ([PR#1530](https://github.com/lbryio/lbry-app/pull/1530))
|
||||||
|
* Fix URI and outpoint not being passed properly to API ([#1494](https://github.com/lbryio/lbry-app/issues/1494))
|
||||||
|
|
||||||
|
|
||||||
## [0.21.3] - 2018-04-23
|
## [0.21.3] - 2018-04-23
|
||||||
|
|
||||||
|
@ -55,7 +63,6 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/).
|
||||||
* App category for Linux ([#877](https://github.com/lbryio/lbry-app/pull/877))
|
* App category for Linux ([#877](https://github.com/lbryio/lbry-app/pull/877))
|
||||||
* Add YouTube Sync reward ([#1147](https://github.com/lbryio/lbry-app/pull/1147))
|
* Add YouTube Sync reward ([#1147](https://github.com/lbryio/lbry-app/pull/1147))
|
||||||
* Retain previous screen sizing on startup ([#338](https://github.com/lbryio/lbry-app/issues/338))
|
* Retain previous screen sizing on startup ([#338](https://github.com/lbryio/lbry-app/issues/338))
|
||||||
* Add 'Go to page' input on channel pagination ([#1166](https://github.com/lbryio/lbry-app/pull/1166))
|
|
||||||
|
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
@ -370,7 +377,6 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/).
|
||||||
* Removed placeholder values from price selection form fields, which was causing confusion that these were real values (#426)
|
* Removed placeholder values from price selection form fields, which was causing confusion that these were real values (#426)
|
||||||
* Fixed showing "other currency" help tip in publish form, which was caused due to not "setting" state for price
|
* Fixed showing "other currency" help tip in publish form, which was caused due to not "setting" state for price
|
||||||
* Publish page now properly checks for all required fields are filled
|
* Publish page now properly checks for all required fields are filled
|
||||||
* Fixed pagination styling for pages > 5 (#416)
|
|
||||||
* Fixed sizing on squat videos (#419)
|
* Fixed sizing on squat videos (#419)
|
||||||
* Support claims no longer show up on Published page (#384)
|
* Support claims no longer show up on Published page (#384)
|
||||||
* Fixed rendering of small prices (#461)
|
* Fixed rendering of small prices (#461)
|
||||||
|
@ -408,7 +414,6 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/).
|
||||||
### Added
|
### Added
|
||||||
* Replaced horizontal scrollbars with scroll arrows
|
* Replaced horizontal scrollbars with scroll arrows
|
||||||
* Featured weekly reward content shows with an orange star
|
* Featured weekly reward content shows with an orange star
|
||||||
* Added pagination to channel pages
|
|
||||||
|
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
# Contribute to LBRY
|
# Contribute to LBRY
|
||||||
|
|
||||||
You found this page! That means you are well on your way to contributing to the LBRY app. This
|
|
||||||
application is primarily written in JavaScript and is built on [Electron](https://electronjs.org)
|
**First:** if you're unsure or afraid of anything, just ask or submit the issue or pull request anyways. You won't be yelled at for giving your best effort. The worst that can happen is that you'll be politely asked to change something. We appreciate any sort of contributions, and don't want a wall of rules to get in the way of that.
|
||||||
while utilizing [React](https://reactjs.org) and [Redux](https://redux.js.org) for UI and
|
|
||||||
application state.
|
However, for those individuals who want a bit more guidance on the best way to contribute to the project, read on. This document will cover what we're looking for. By addressing all the points we're looking for, it raises the chances we can quickly merge or address your contributions.
|
||||||
|
|
||||||
|
|
||||||
## TL;DR?
|
## TL;DR?
|
||||||
|
@ -57,10 +57,19 @@ Although all contributions should have good UX, the [UX label, when applied in c
|
||||||
|
|
||||||
The entry point for this application is `src/renderer/index.js`
|
The entry point for this application is `src/renderer/index.js`
|
||||||
|
|
||||||
|
This application is primarily written in JavaScript and is built on [Electron](https://electronjs.org)
|
||||||
|
while utilizing [React](https://reactjs.org) and [Redux](https://redux.js.org) for UI and
|
||||||
|
application state.
|
||||||
|
|
||||||
The project comes with diverse tools for simplifying the development process and for providing
|
The project comes with diverse tools for simplifying the development process and for providing
|
||||||
better code quality. It's recommended to make use of them thoroughly during ongoing development. We follow the well-known [Airbnb JavaScript Style Guide](http://airbnb.io/javascript/) for defining
|
better code quality. It's recommended to make use of them thoroughly during ongoing development. We follow the well-known [Airbnb JavaScript Style Guide](http://airbnb.io/javascript/) for defining
|
||||||
our styling rules and code best practices.
|
our styling rules and code best practices.
|
||||||
|
|
||||||
|
### lbry-redux
|
||||||
|
|
||||||
|
This project uses [lbry-redux](https://github.com/lbryio/lbry-redux) to share Redux code with [lbry-android](https://github.com/lbryio/lbry-android) and other LBRY apps. Over time, more Redux code that is suitable to be shared will be moved into lbry-redux. If modifying Redux code, you may be asked to make some of your changes in lbry-redux rather than lbry-app. The steps to work with lbry-redux locally can be found [here](https://github.com/lbryio/lbry-redux#local-development).
|
||||||
|
|
||||||
|
|
||||||
### Flow
|
### Flow
|
||||||
|
|
||||||
[Flow](https://flow.org/) is a static type checker for JavaScript. Flow checks your code for
|
[Flow](https://flow.org/) is a static type checker for JavaScript. Flow checks your code for
|
||||||
|
@ -137,6 +146,8 @@ There are a few tools integrated to the project that will ease the process of de
|
||||||
manner and, therefore, not begin working on anything reserved (or updated) within the last 3 days.
|
manner and, therefore, not begin working on anything reserved (or updated) within the last 3 days.
|
||||||
If someone has been officially assigned an issue via Github's assignment system, it is also not
|
If someone has been officially assigned an issue via Github's assignment system, it is also not
|
||||||
available. Contributors are encouraged to ask if they have any questions about issue availability.
|
available. Contributors are encouraged to ask if they have any questions about issue availability.
|
||||||
|
* The [changelog](https://github.com/lbryio/lbry-app/blob/master/CHANGELOG.md) should be updated to
|
||||||
|
include a referene to the fix/change/addition. See previous entries for format.
|
||||||
* Once the pull request is visible in the LBRY repo, a LBRY team member will review it and make sure
|
* Once the pull request is visible in the LBRY repo, a LBRY team member will review it and make sure
|
||||||
it is up to our standards. At this point, the contributor may have to change his or her code based
|
it is up to our standards. At this point, the contributor may have to change his or her code based
|
||||||
on our suggestions and comments.
|
on our suggestions and comments.
|
||||||
|
@ -172,7 +183,7 @@ will earn you an extra 50 LBC on top of what we would otherwise tip you.
|
||||||
| Name | Role | Discord | Email |
|
| Name | Role | Discord | Email |
|
||||||
| --------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------- | ------------
|
| --------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------- | ------------
|
||||||
| [Tom](https://github.com/tzarebczan) | Community manager. He knows more than anyone about the app and all of its flaws. Reach out to him with any questions about how the app works, if a bug has been reported, or if a feature should be requested. | jiggytom | tom@lbry.io |
|
| [Tom](https://github.com/tzarebczan) | Community manager. He knows more than anyone about the app and all of its flaws. Reach out to him with any questions about how the app works, if a bug has been reported, or if a feature should be requested. | jiggytom | tom@lbry.io |
|
||||||
| [Sean](https://github.com/seanyesmunt) | The primary engineer working on the app. Feel free to ask any questions about how the code. | sean | sean@lbry.io |
|
| [Sean](https://github.com/seanyesmunt) | The primary engineer working on the app. Feel free to ask any questions about the code. | sean | sean@lbry.io |
|
||||||
|
|
||||||
Join our Discord [here](https://chat.lbry.io/).
|
Join our Discord [here](https://chat.lbry.io/).
|
||||||
|
|
||||||
|
|
|
@ -48,6 +48,10 @@ Double click the installed application to browse with the LBRY network.
|
||||||
If you want to just build the app you can run `yarn build`. This will give you an executable inside the `/dist` folder. We use [electron-builder](https://github.com/electron-userland/electron-builder) to create
|
If you want to just build the app you can run `yarn build`. This will give you an executable inside the `/dist` folder. We use [electron-builder](https://github.com/electron-userland/electron-builder) to create
|
||||||
distributable packages.
|
distributable packages.
|
||||||
|
|
||||||
|
#### Resetting your Packages
|
||||||
|
|
||||||
|
If the app isn't building, or `yarn xxx` commands aren't working you may need to just reset your `node_modules`. To do so you can run: `rm -r node_modules && yarn` or `del /s /q node_modules && yarn` on Windows.
|
||||||
|
|
||||||
## Contributing
|
## Contributing
|
||||||
|
|
||||||
Contributions to this project are welcome, encouraged, and compensated. For more details, see [CONTRIBUTING.md](CONTRIBUTING.md)
|
Contributions to this project are welcome, encouraged, and compensated. For more details, see [CONTRIBUTING.md](CONTRIBUTING.md)
|
||||||
|
|
|
@ -30,9 +30,6 @@
|
||||||
"flow-defs": "flow-typed install",
|
"flow-defs": "flow-typed install",
|
||||||
"release": "yarn compile && electron-builder build",
|
"release": "yarn compile && electron-builder build",
|
||||||
"precommit": "lint-staged",
|
"precommit": "lint-staged",
|
||||||
"postmerge": "yarnhook",
|
|
||||||
"postcheckout": "yarnhook",
|
|
||||||
"postrewrite": "yarnhook",
|
|
||||||
"postinstall": "electron-builder install-app-deps & node build/downloadDaemon.js",
|
"postinstall": "electron-builder install-app-deps & node build/downloadDaemon.js",
|
||||||
"clean": "rm -r node_modules && yarn cache clean lbry-redux && yarn"
|
"clean": "rm -r node_modules && yarn cache clean lbry-redux && yarn"
|
||||||
},
|
},
|
||||||
|
@ -51,7 +48,7 @@
|
||||||
"formik": "^0.10.4",
|
"formik": "^0.10.4",
|
||||||
"hast-util-sanitize": "^1.1.2",
|
"hast-util-sanitize": "^1.1.2",
|
||||||
"keytar": "^4.2.1",
|
"keytar": "^4.2.1",
|
||||||
"lbry-redux": "lbryio/lbry-redux#86530690e93a4cfb702ade32d9f2121ccbca47a6",
|
"lbry-redux": "lbryio/lbry-redux#543af2fcee7e4c45ccaf73af7b47d4b1a5d8ad44",
|
||||||
"localforage": "^1.7.1",
|
"localforage": "^1.7.1",
|
||||||
"mixpanel-browser": "^2.17.1",
|
"mixpanel-browser": "^2.17.1",
|
||||||
"moment": "^2.22.0",
|
"moment": "^2.22.0",
|
||||||
|
@ -74,7 +71,7 @@
|
||||||
"redux-thunk": "^2.2.0",
|
"redux-thunk": "^2.2.0",
|
||||||
"remark": "^9.0.0",
|
"remark": "^9.0.0",
|
||||||
"remark-react": "^4.0.3",
|
"remark-react": "^4.0.3",
|
||||||
"render-media": "^2.12.0",
|
"render-media": "^3.1.0",
|
||||||
"reselect": "^3.0.0",
|
"reselect": "^3.0.0",
|
||||||
"semver": "^5.3.0",
|
"semver": "^5.3.0",
|
||||||
"shapeshift.io": "^1.3.1",
|
"shapeshift.io": "^1.3.1",
|
||||||
|
|
|
@ -3,7 +3,6 @@ import isDev from 'electron-is-dev';
|
||||||
import windowStateKeeper from 'electron-window-state';
|
import windowStateKeeper from 'electron-window-state';
|
||||||
|
|
||||||
import setupBarMenu from './menu/setupBarMenu';
|
import setupBarMenu from './menu/setupBarMenu';
|
||||||
import setupContextMenu from './menu/setupContextMenu';
|
|
||||||
|
|
||||||
export default appState => {
|
export default appState => {
|
||||||
// Get primary display dimensions from Electron.
|
// Get primary display dimensions from Electron.
|
||||||
|
@ -65,15 +64,18 @@ export default appState => {
|
||||||
// path, so we just strip it off.
|
// path, so we just strip it off.
|
||||||
// - In a URI with a claim ID, like lbry://channel#claimid, Windows interprets the hash mark as
|
// - In a URI with a claim ID, like lbry://channel#claimid, Windows interprets the hash mark as
|
||||||
// an anchor and converts it to lbry://channel/#claimid. We remove the slash here as well.
|
// an anchor and converts it to lbry://channel/#claimid. We remove the slash here as well.
|
||||||
|
// - ? also interpreted as an anchor, remove slash also.
|
||||||
if (process.platform === 'win32') {
|
if (process.platform === 'win32') {
|
||||||
deepLinkingURI = deepLinkingURI.replace(/\/$/, '').replace('/#', '#');
|
deepLinkingURI = deepLinkingURI
|
||||||
|
.replace(/\/$/, '')
|
||||||
|
.replace('/#', '#')
|
||||||
|
.replace('/?', '?');
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
deepLinkingURI = appState.macDeepLinkingURI;
|
deepLinkingURI = appState.macDeepLinkingURI;
|
||||||
}
|
}
|
||||||
|
|
||||||
setupBarMenu();
|
setupBarMenu();
|
||||||
setupContextMenu(window);
|
|
||||||
|
|
||||||
window.on('close', event => {
|
window.on('close', event => {
|
||||||
if (!appState.isQuitting && !appState.autoUpdateAccepted) {
|
if (!appState.isQuitting && !appState.autoUpdateAccepted) {
|
||||||
|
|
|
@ -75,6 +75,9 @@ app.on('ready', async () => {
|
||||||
await installExtensions();
|
await installExtensions();
|
||||||
}
|
}
|
||||||
rendererWindow = createWindow(appState);
|
rendererWindow = createWindow(appState);
|
||||||
|
rendererWindow.webContents.on('devtools-opened', () => {
|
||||||
|
rendererWindow.webContents.send('devtools-is-opened');
|
||||||
|
});
|
||||||
tray = createTray(rendererWindow);
|
tray = createTray(rendererWindow);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -176,11 +179,11 @@ ipcMain.on('version-info-requested', () => {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
let result = '';
|
let result = '';
|
||||||
|
const onSuccess = res => {
|
||||||
const req = https.get(Object.assign(opts, url.parse(latestReleaseAPIURL)), res => {
|
|
||||||
res.on('data', data => {
|
res.on('data', data => {
|
||||||
result += data;
|
result += data;
|
||||||
});
|
});
|
||||||
|
|
||||||
res.on('end', () => {
|
res.on('end', () => {
|
||||||
const tagName = JSON.parse(result).tag_name;
|
const tagName = JSON.parse(result).tag_name;
|
||||||
const [, remoteVersion] = tagName.match(/^v([\d.]+(?:-?rc\d+)?)$/);
|
const [, remoteVersion] = tagName.match(/^v([\d.]+(?:-?rc\d+)?)$/);
|
||||||
|
@ -199,14 +202,27 @@ ipcMain.on('version-info-requested', () => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
};
|
||||||
|
|
||||||
req.on('error', err => {
|
const requestLatestRelease = (apiUrl, alreadyRedirected = false) => {
|
||||||
console.log('Failed to get current version from GitHub. Error:', err);
|
const req = https.get(Object.assign(opts, url.parse(apiUrl)), res => {
|
||||||
if (rendererWindow) {
|
if (res.statusCode === 301 || res.statusCode === 302) {
|
||||||
rendererWindow.webContents.send('version-info-received', null);
|
requestLatestRelease(res.headers.location, true);
|
||||||
}
|
} else {
|
||||||
});
|
onSuccess(res);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (alreadyRedirected) return;
|
||||||
|
req.on('error', err => {
|
||||||
|
console.log('Failed to get current version from GitHub. Error:', err);
|
||||||
|
if (rendererWindow) {
|
||||||
|
rendererWindow.webContents.send('version-info-received', null);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
requestLatestRelease(latestReleaseAPIURL);
|
||||||
});
|
});
|
||||||
|
|
||||||
ipcMain.on('get-auth-token', event => {
|
ipcMain.on('get-auth-token', event => {
|
||||||
|
@ -242,8 +258,11 @@ const isSecondInstance = app.makeSingleInstance(argv => {
|
||||||
// path, so we just strip it off.
|
// path, so we just strip it off.
|
||||||
// - In a URI with a claim ID, like lbry://channel#claimid, Windows interprets the hash mark as
|
// - In a URI with a claim ID, like lbry://channel#claimid, Windows interprets the hash mark as
|
||||||
// an anchor and converts it to lbry://channel/#claimid. We remove the slash here as well.
|
// an anchor and converts it to lbry://channel/#claimid. We remove the slash here as well.
|
||||||
|
// - ? also interpreted as an anchor, remove slash also.
|
||||||
if (process.platform === 'win32') {
|
if (process.platform === 'win32') {
|
||||||
URI = URI.replace(/\/$/, '').replace('/#', '#');
|
URI = URI.replace(/\/$/, '')
|
||||||
|
.replace('/#', '#')
|
||||||
|
.replace('/?', '?');
|
||||||
}
|
}
|
||||||
|
|
||||||
rendererWindow.webContents.send('open-uri-requested', URI);
|
rendererWindow.webContents.send('open-uri-requested', URI);
|
||||||
|
|
|
@ -1,27 +0,0 @@
|
||||||
// @flow
|
|
||||||
import { Menu, BrowserWindow } from 'electron';
|
|
||||||
import isDev from 'electron-is-dev';
|
|
||||||
|
|
||||||
export default (rendererWindow: BrowserWindow) => {
|
|
||||||
rendererWindow.webContents.on('context-menu', (e, params) => {
|
|
||||||
const { x, y } = params;
|
|
||||||
|
|
||||||
const template = [{ role: 'cut' }, { role: 'copy' }, { role: 'paste' }];
|
|
||||||
|
|
||||||
const developmentTemplateAddition = [
|
|
||||||
{ type: 'separator' },
|
|
||||||
{
|
|
||||||
label: 'Inspect element',
|
|
||||||
click: () => {
|
|
||||||
rendererWindow.inspectElement(x, y);
|
|
||||||
},
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
if (isDev) {
|
|
||||||
template.push(...developmentTemplateAddition);
|
|
||||||
}
|
|
||||||
|
|
||||||
Menu.buildFromTemplate(template).popup();
|
|
||||||
});
|
|
||||||
};
|
|
|
@ -7,6 +7,7 @@ import ReactModal from 'react-modal';
|
||||||
import throttle from 'util/throttle';
|
import throttle from 'util/throttle';
|
||||||
import SideBar from 'component/sideBar';
|
import SideBar from 'component/sideBar';
|
||||||
import Header from 'component/header';
|
import Header from 'component/header';
|
||||||
|
import { openContextMenu } from '../../util/contextMenu';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
alertError: (string | {}) => void,
|
alertError: (string | {}) => void,
|
||||||
|
@ -79,7 +80,7 @@ class App extends React.PureComponent<Props> {
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<div id="window">
|
<div id="window" onContextMenu={e => openContextMenu(e)}>
|
||||||
<Theme />
|
<Theme />
|
||||||
<main className="page">
|
<main className="page">
|
||||||
<SideBar />
|
<SideBar />
|
||||||
|
|
|
@ -22,6 +22,7 @@ type Props = {
|
||||||
button: ?string, // primary, secondary, alt, link
|
button: ?string, // primary, secondary, alt, link
|
||||||
noPadding: ?boolean, // to remove padding and allow circular buttons
|
noPadding: ?boolean, // to remove padding and allow circular buttons
|
||||||
uppercase: ?boolean,
|
uppercase: ?boolean,
|
||||||
|
iconColor: ?string,
|
||||||
};
|
};
|
||||||
|
|
||||||
class Button extends React.PureComponent<Props> {
|
class Button extends React.PureComponent<Props> {
|
||||||
|
@ -48,6 +49,7 @@ class Button extends React.PureComponent<Props> {
|
||||||
type,
|
type,
|
||||||
noPadding,
|
noPadding,
|
||||||
uppercase,
|
uppercase,
|
||||||
|
iconColor,
|
||||||
...otherProps
|
...otherProps
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
|
@ -82,10 +84,10 @@ class Button extends React.PureComponent<Props> {
|
||||||
|
|
||||||
const content = (
|
const content = (
|
||||||
<span className="btn__content">
|
<span className="btn__content">
|
||||||
{icon && <Icon icon={icon} />}
|
{icon && <Icon icon={icon} iconColor={iconColor} />}
|
||||||
{label && <span className="btn__label">{label}</span>}
|
{label && <span className="btn__label">{label}</span>}
|
||||||
{children && children}
|
{children && children}
|
||||||
{iconRight && <Icon icon={iconRight} />}
|
{iconRight && <Icon icon={iconRight} iconColor={iconColor} />}
|
||||||
</span>
|
</span>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
18
src/renderer/component/categoryList/index.js
Normal file
18
src/renderer/component/categoryList/index.js
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
import { connect } from 'react-redux';
|
||||||
|
import { doFetchClaimsByChannel } from 'redux/actions/content';
|
||||||
|
import {
|
||||||
|
makeSelectClaimsInChannelForCurrentPage,
|
||||||
|
makeSelectFetchingChannelClaims,
|
||||||
|
} from 'lbry-redux';
|
||||||
|
import CategoryList from './view';
|
||||||
|
|
||||||
|
const select = (state, props) => ({
|
||||||
|
channelClaims: makeSelectClaimsInChannelForCurrentPage(props.categoryLink)(state),
|
||||||
|
fetching: makeSelectFetchingChannelClaims(props.categoryLink)(state),
|
||||||
|
});
|
||||||
|
|
||||||
|
const perform = dispatch => ({
|
||||||
|
fetchChannel: channel => dispatch(doFetchClaimsByChannel(channel)),
|
||||||
|
});
|
||||||
|
|
||||||
|
export default connect(select, perform)(CategoryList);
|
|
@ -5,11 +5,15 @@ import ToolTip from 'component/common/tooltip';
|
||||||
import FileCard from 'component/fileCard';
|
import FileCard from 'component/fileCard';
|
||||||
import Button from 'component/button';
|
import Button from 'component/button';
|
||||||
import * as icons from 'constants/icons';
|
import * as icons from 'constants/icons';
|
||||||
|
import Claim from 'types/claim';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
category: string,
|
category: string,
|
||||||
names: Array<string>,
|
names: Array<string>,
|
||||||
categoryLink?: string,
|
categoryLink: ?string,
|
||||||
|
fetching: boolean,
|
||||||
|
channelClaims: Array<Claim>,
|
||||||
|
fetchChannel: string => void,
|
||||||
};
|
};
|
||||||
|
|
||||||
type State = {
|
type State = {
|
||||||
|
@ -18,6 +22,11 @@ type State = {
|
||||||
};
|
};
|
||||||
|
|
||||||
class CategoryList extends React.PureComponent<Props, State> {
|
class CategoryList extends React.PureComponent<Props, State> {
|
||||||
|
static defaultProps = {
|
||||||
|
names: [],
|
||||||
|
categoryLink: '',
|
||||||
|
};
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
|
@ -32,6 +41,11 @@ class CategoryList extends React.PureComponent<Props, State> {
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
|
const { fetching, categoryLink, fetchChannel } = this.props;
|
||||||
|
if (!fetching && categoryLink) {
|
||||||
|
fetchChannel(categoryLink);
|
||||||
|
}
|
||||||
|
|
||||||
const cardRow = this.rowItems;
|
const cardRow = this.rowItems;
|
||||||
if (cardRow) {
|
if (cardRow) {
|
||||||
const cards = cardRow.getElementsByTagName('section');
|
const cards = cardRow.getElementsByTagName('section');
|
||||||
|
@ -109,6 +123,9 @@ class CategoryList extends React.PureComponent<Props, State> {
|
||||||
|
|
||||||
// check if a card is fully visible horizontally
|
// check if a card is fully visible horizontally
|
||||||
isCardVisible = (section: HTMLElement) => {
|
isCardVisible = (section: HTMLElement) => {
|
||||||
|
if (!section) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
const rect = section.getBoundingClientRect();
|
const rect = section.getBoundingClientRect();
|
||||||
const isVisible = rect.left >= 0 && rect.right <= window.innerWidth;
|
const isVisible = rect.left >= 0 && rect.right <= window.innerWidth;
|
||||||
return isVisible;
|
return isVisible;
|
||||||
|
@ -189,7 +206,7 @@ class CategoryList extends React.PureComponent<Props, State> {
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { category, names, categoryLink } = this.props;
|
const { category, categoryLink, names, channelClaims } = this.props;
|
||||||
const { canScrollNext, canScrollPrevious } = this.state;
|
const { canScrollNext, canScrollPrevious } = this.state;
|
||||||
|
|
||||||
// The lint was throwing an error saying we should use <button> instead of <a>
|
// The lint was throwing an error saying we should use <button> instead of <a>
|
||||||
|
@ -235,6 +252,12 @@ class CategoryList extends React.PureComponent<Props, State> {
|
||||||
className="card-row__scrollhouse"
|
className="card-row__scrollhouse"
|
||||||
>
|
>
|
||||||
{names && names.map(name => <FileCard key={name} uri={normalizeURI(name)} />)}
|
{names && names.map(name => <FileCard key={name} uri={normalizeURI(name)} />)}
|
||||||
|
|
||||||
|
{channelClaims && channelClaims.length
|
||||||
|
? channelClaims.map(claim => (
|
||||||
|
<FileCard key={claim.claim_id} uri={`lbry://${claim.name}#${claim.claim_id}`} />
|
||||||
|
))
|
||||||
|
: null}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
|
@ -62,7 +62,6 @@ export class FormFieldPrice extends React.PureComponent<Props> {
|
||||||
name={`${name}_currency`}
|
name={`${name}_currency`}
|
||||||
type="select"
|
type="select"
|
||||||
id={`${name}_currency`}
|
id={`${name}_currency`}
|
||||||
className="form-field"
|
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
onChange={this.handleCurrencyChange}
|
onChange={this.handleCurrencyChange}
|
||||||
value={price.currency}
|
value={price.currency}
|
||||||
|
|
|
@ -42,7 +42,7 @@ export class FormField extends React.PureComponent<Props> {
|
||||||
if (type) {
|
if (type) {
|
||||||
if (type === 'select') {
|
if (type === 'select') {
|
||||||
input = (
|
input = (
|
||||||
<select id={name} {...inputProps}>
|
<select className="form-field__select" id={name} {...inputProps}>
|
||||||
{children}
|
{children}
|
||||||
</select>
|
</select>
|
||||||
);
|
);
|
||||||
|
|
|
@ -4,7 +4,6 @@ import * as React from 'react';
|
||||||
import classnames from 'classnames';
|
import classnames from 'classnames';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
centered?: boolean,
|
|
||||||
children: React.Node,
|
children: React.Node,
|
||||||
padded?: boolean,
|
padded?: boolean,
|
||||||
verticallyCentered?: boolean,
|
verticallyCentered?: boolean,
|
||||||
|
@ -22,7 +21,6 @@ export class FormRow extends React.PureComponent<Props> {
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={classnames('form-row', {
|
className={classnames('form-row', {
|
||||||
'form-row--centered': centered,
|
|
||||||
'form-row--padded': padded,
|
'form-row--padded': padded,
|
||||||
'form-row--vertically-centered': verticallyCentered,
|
'form-row--vertically-centered': verticallyCentered,
|
||||||
'form-row--stretch': stretch,
|
'form-row--stretch': stretch,
|
||||||
|
|
|
@ -1,34 +1,72 @@
|
||||||
// @flow
|
// @flow
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
// import * as icons from 'constants/icons';
|
|
||||||
import * as FeatherIcons from 'react-feather';
|
import * as FeatherIcons from 'react-feather';
|
||||||
import * as icons from 'constants/icons';
|
import * as icons from 'constants/icons';
|
||||||
|
import Tooltip from 'component/common/tooltip';
|
||||||
|
|
||||||
const RED_COLOR = '#e2495e';
|
const RED_COLOR = '#e2495e';
|
||||||
|
const PURPLE_COLOR = '#8165b0';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
icon: string,
|
icon: string,
|
||||||
|
tooltip?: string, // tooltip direction
|
||||||
|
iconColor?: string,
|
||||||
};
|
};
|
||||||
|
|
||||||
class IconComponent extends React.PureComponent<Props> {
|
class IconComponent extends React.PureComponent<Props> {
|
||||||
// TODO: Move all icons to constants and add titles for all
|
getTooltip = (icon: string) => {
|
||||||
// Add some some sort of hover flyout with the title?
|
switch (icon) {
|
||||||
|
case icons.FEATURED:
|
||||||
|
return __('Featured content. Earn rewards for watching.');
|
||||||
|
case icons.LOCAL:
|
||||||
|
return __('This file is downloaded.');
|
||||||
|
default:
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
getIconColor = (color: string) => {
|
||||||
|
switch (color) {
|
||||||
|
case 'red':
|
||||||
|
return RED_COLOR;
|
||||||
|
case 'purple':
|
||||||
|
return PURPLE_COLOR;
|
||||||
|
default:
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { icon } = this.props;
|
const { icon, tooltip, iconColor } = this.props;
|
||||||
const Icon = FeatherIcons[icon];
|
const Icon = FeatherIcons[icon];
|
||||||
|
|
||||||
|
if (!Icon) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
let color;
|
let color;
|
||||||
if (icon === icons.HEART || icon === icons.FEATURED) {
|
if (iconColor) {
|
||||||
color = RED_COLOR;
|
color = this.getIconColor(iconColor);
|
||||||
}
|
}
|
||||||
|
|
||||||
let size = 14;
|
let size = 14;
|
||||||
if (icon === icons.ARROW_LEFT || icon === icons.ARROW_RIGHT) {
|
if (icon === icons.ARROW_LEFT || icon === icons.ARROW_RIGHT) {
|
||||||
size = 18;
|
size = 20;
|
||||||
}
|
}
|
||||||
|
|
||||||
return Icon ? <Icon size={size} className="icon" color={color} /> : null;
|
let tooltipText;
|
||||||
|
if (tooltip) {
|
||||||
|
tooltipText = this.getTooltip(icon);
|
||||||
|
}
|
||||||
|
const inner = <Icon size={size} className="icon" color={color} />;
|
||||||
|
|
||||||
|
return tooltip ? (
|
||||||
|
<Tooltip icon body={tooltipText} direction={tooltip}>
|
||||||
|
{inner}
|
||||||
|
</Tooltip>
|
||||||
|
) : (
|
||||||
|
inner
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,55 +1,38 @@
|
||||||
// @flow
|
// @flow
|
||||||
import React from 'react';
|
import * as React from 'react';
|
||||||
import classnames from 'classnames';
|
import classnames from 'classnames';
|
||||||
import Icon from 'component/common/icon';
|
|
||||||
import Button from 'component/button';
|
|
||||||
import * as icons from 'constants/icons';
|
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
body: string,
|
body: string,
|
||||||
label: string,
|
label?: string,
|
||||||
|
children: ?React.Node,
|
||||||
|
icon: ?boolean,
|
||||||
|
direction: string,
|
||||||
};
|
};
|
||||||
|
|
||||||
type State = {
|
class ToolTip extends React.PureComponent<Props> {
|
||||||
showTooltip: boolean,
|
static defaultProps = {
|
||||||
};
|
direction: 'bottom',
|
||||||
|
};
|
||||||
class ToolTip extends React.PureComponent<Props, State> {
|
|
||||||
constructor(props: Props) {
|
|
||||||
super(props);
|
|
||||||
|
|
||||||
this.state = {
|
|
||||||
showTooltip: false,
|
|
||||||
};
|
|
||||||
|
|
||||||
(this: any).handleClick = this.handleClick.bind(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
handleClick() {
|
|
||||||
const { showTooltip } = this.state;
|
|
||||||
|
|
||||||
if (!showTooltip) {
|
|
||||||
document.addEventListener('click', this.handleClick);
|
|
||||||
} else {
|
|
||||||
document.removeEventListener('click', this.handleClick);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.setState({
|
|
||||||
showTooltip: !showTooltip,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { label, body } = this.props;
|
const { children, label, body, icon, direction } = this.props;
|
||||||
const { showTooltip } = this.state;
|
|
||||||
|
const tooltipContent = children || label;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<span className="tooltip">
|
<span
|
||||||
<Button button="link" className="help tooltip__link" onClick={this.handleClick}>
|
className={classnames('tooltip', {
|
||||||
{label}
|
'tooltip--label': label && !icon,
|
||||||
{showTooltip && <Icon icon={icons.CLOSE} />}
|
'tooltip--icon': icon,
|
||||||
</Button>
|
'tooltip--top': direction === 'top',
|
||||||
<div className={classnames('tooltip__body', { hidden: !showTooltip })}>{body}</div>
|
'tooltip--right': direction === 'right',
|
||||||
|
'tooltip--bottom': direction === 'bottom',
|
||||||
|
'tooltip--left': direction === 'left',
|
||||||
|
})}
|
||||||
|
>
|
||||||
|
{tooltipContent}
|
||||||
|
<span className="tooltip__body">{body}</span>
|
||||||
</span>
|
</span>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,7 +19,6 @@ class ExternalLink extends React.PureComponent<Props> {
|
||||||
|
|
||||||
createLink() {
|
createLink() {
|
||||||
const { href, title, children, openModal, navigate } = this.props;
|
const { href, title, children, openModal, navigate } = this.props;
|
||||||
console.info(href);
|
|
||||||
|
|
||||||
// Regex for url protocol
|
// Regex for url protocol
|
||||||
const protocolRegex = new RegExp('^(https?|lbry)+:', 'i');
|
const protocolRegex = new RegExp('^(https?|lbry)+:', 'i');
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
// @flow
|
// @flow
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import Button from 'component/button';
|
import Button from 'component/button';
|
||||||
import FileDownloadLink from 'component/fileDownloadLink';
|
|
||||||
import { MODALS } from 'lbry-redux';
|
import { MODALS } from 'lbry-redux';
|
||||||
import classnames from 'classnames';
|
import classnames from 'classnames';
|
||||||
import * as icons from 'constants/icons';
|
import * as icons from 'constants/icons';
|
||||||
|
@ -12,6 +11,7 @@ type FileInfo = {
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
uri: string,
|
uri: string,
|
||||||
|
claimId: string,
|
||||||
openModal: ({ id: string }, { uri: string }) => void,
|
openModal: ({ id: string }, { uri: string }) => void,
|
||||||
claimIsMine: boolean,
|
claimIsMine: boolean,
|
||||||
fileInfo: FileInfo,
|
fileInfo: FileInfo,
|
||||||
|
@ -20,28 +20,26 @@ type Props = {
|
||||||
|
|
||||||
class FileActions extends React.PureComponent<Props> {
|
class FileActions extends React.PureComponent<Props> {
|
||||||
render() {
|
render() {
|
||||||
const { fileInfo, uri, openModal, claimIsMine, vertical } = this.props;
|
const { fileInfo, uri, openModal, claimIsMine, vertical, claimId } = this.props;
|
||||||
|
|
||||||
const claimId = fileInfo ? fileInfo.claim_id : '';
|
|
||||||
const showDelete = fileInfo && Object.keys(fileInfo).length > 0;
|
const showDelete = fileInfo && Object.keys(fileInfo).length > 0;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section className={classnames('card__actions', { 'card__actions--vertical': vertical })}>
|
<section className={classnames('card__actions', { 'card__actions--vertical': vertical })}>
|
||||||
<FileDownloadLink uri={uri} />
|
|
||||||
{showDelete && (
|
{showDelete && (
|
||||||
<Button
|
<Button
|
||||||
className="btn--file-actions"
|
button="alt"
|
||||||
icon={icons.TRASH}
|
icon={icons.TRASH}
|
||||||
description={__('Delete')}
|
iconColor="red"
|
||||||
|
label={__('Delete')}
|
||||||
onClick={() => openModal({ id: MODALS.CONFIRM_FILE_REMOVE }, { uri })}
|
onClick={() => openModal({ id: MODALS.CONFIRM_FILE_REMOVE }, { uri })}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{!claimIsMine && (
|
{!claimIsMine && (
|
||||||
<Button
|
<Button
|
||||||
className="btn--file-actions"
|
button="alt"
|
||||||
icon={icons.REPORT}
|
icon={icons.REPORT}
|
||||||
href={`https://lbry.io/dmca?claim_id=${claimId}`}
|
href={`https://lbry.io/dmca?claim_id=${claimId}`}
|
||||||
description={__('Report content')}
|
label={__('Report content')}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</section>
|
</section>
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// @flow
|
// @flow
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import { normalizeURI } from 'lbry-redux';
|
import { normalizeURI, convertToShareLink } from 'lbry-redux';
|
||||||
import Button from 'component/button';
|
import Button from 'component/button';
|
||||||
import CardMedia from 'component/cardMedia';
|
import CardMedia from 'component/cardMedia';
|
||||||
import TruncatedText from 'component/common/truncated-text';
|
import TruncatedText from 'component/common/truncated-text';
|
||||||
|
@ -9,6 +9,7 @@ import FilePrice from 'component/filePrice';
|
||||||
import UriIndicator from 'component/uriIndicator';
|
import UriIndicator from 'component/uriIndicator';
|
||||||
import * as icons from 'constants/icons';
|
import * as icons from 'constants/icons';
|
||||||
import classnames from 'classnames';
|
import classnames from 'classnames';
|
||||||
|
import { openCopyLinkMenu } from '../../util/contextMenu';
|
||||||
|
|
||||||
// TODO: iron these out
|
// TODO: iron these out
|
||||||
type Props = {
|
type Props = {
|
||||||
|
@ -60,6 +61,11 @@ class FileCard extends React.PureComponent<Props> {
|
||||||
const thumbnail = metadata && metadata.thumbnail ? metadata.thumbnail : null;
|
const thumbnail = metadata && metadata.thumbnail ? metadata.thumbnail : null;
|
||||||
const shouldObscureNsfw = obscureNsfw && metadata && metadata.nsfw;
|
const shouldObscureNsfw = obscureNsfw && metadata && metadata.nsfw;
|
||||||
const isRewardContent = claim && rewardedContentClaimIds.includes(claim.claim_id);
|
const isRewardContent = claim && rewardedContentClaimIds.includes(claim.claim_id);
|
||||||
|
const handleContextMenu = event => {
|
||||||
|
event.preventDefault();
|
||||||
|
event.stopPropagation();
|
||||||
|
openCopyLinkMenu(convertToShareLink(uri), event);
|
||||||
|
};
|
||||||
|
|
||||||
// We should be able to tab through cards
|
// We should be able to tab through cards
|
||||||
/* eslint-disable jsx-a11y/click-events-have-key-events */
|
/* eslint-disable jsx-a11y/click-events-have-key-events */
|
||||||
|
@ -72,6 +78,7 @@ class FileCard extends React.PureComponent<Props> {
|
||||||
'card--link': !pending,
|
'card--link': !pending,
|
||||||
'card--pending': pending,
|
'card--pending': pending,
|
||||||
})}
|
})}
|
||||||
|
onContextMenu={handleContextMenu}
|
||||||
>
|
>
|
||||||
<CardMedia nsfw={shouldObscureNsfw} thumbnail={thumbnail} />
|
<CardMedia nsfw={shouldObscureNsfw} thumbnail={thumbnail} />
|
||||||
<div className="card-media__internal-links">{showPrice && <FilePrice uri={uri} />}</div>
|
<div className="card-media__internal-links">{showPrice && <FilePrice uri={uri} />}</div>
|
||||||
|
@ -98,14 +105,16 @@ class FileCard extends React.PureComponent<Props> {
|
||||||
<div className="card__title--small">
|
<div className="card__title--small">
|
||||||
<TruncatedText lines={3}>{title}</TruncatedText>
|
<TruncatedText lines={3}>{title}</TruncatedText>
|
||||||
</div>
|
</div>
|
||||||
<div className="card__subtitle card__subtitle--file-info">
|
<div className="card__subtitle">
|
||||||
{pending ? (
|
{pending ? (
|
||||||
<div>Pending...</div>
|
<div>Pending...</div>
|
||||||
) : (
|
) : (
|
||||||
<React.Fragment>
|
<React.Fragment>
|
||||||
<UriIndicator uri={uri} link />
|
<UriIndicator uri={uri} link />
|
||||||
{isRewardContent && <Icon icon={icons.FEATURED} />}
|
<div>
|
||||||
{fileInfo && <Icon icon={icons.LOCAL} />}
|
{isRewardContent && <Icon iconColor="red" icon={icons.FEATURED} />}
|
||||||
|
{fileInfo && <Icon icon={icons.LOCAL} />}
|
||||||
|
</div>
|
||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -5,7 +5,6 @@ import {
|
||||||
makeSelectLoadingForUri,
|
makeSelectLoadingForUri,
|
||||||
makeSelectCostInfoForUri,
|
makeSelectCostInfoForUri,
|
||||||
} from 'lbry-redux';
|
} from 'lbry-redux';
|
||||||
import { doFetchAvailability } from 'redux/actions/availability';
|
|
||||||
import { doOpenFileInShell } from 'redux/actions/file';
|
import { doOpenFileInShell } from 'redux/actions/file';
|
||||||
import { doPurchaseUri, doStartDownload } from 'redux/actions/content';
|
import { doPurchaseUri, doStartDownload } from 'redux/actions/content';
|
||||||
import { doPause } from 'redux/actions/media';
|
import { doPause } from 'redux/actions/media';
|
||||||
|
@ -20,7 +19,6 @@ const select = (state, props) => ({
|
||||||
});
|
});
|
||||||
|
|
||||||
const perform = dispatch => ({
|
const perform = dispatch => ({
|
||||||
checkAvailability: uri => dispatch(doFetchAvailability(uri)),
|
|
||||||
openInShell: path => dispatch(doOpenFileInShell(path)),
|
openInShell: path => dispatch(doOpenFileInShell(path)),
|
||||||
purchaseUri: uri => dispatch(doPurchaseUri(uri)),
|
purchaseUri: uri => dispatch(doPurchaseUri(uri)),
|
||||||
restartDownload: (uri, outpoint) => dispatch(doStartDownload(uri, outpoint)),
|
restartDownload: (uri, outpoint) => dispatch(doStartDownload(uri, outpoint)),
|
||||||
|
|
|
@ -1,21 +1,29 @@
|
||||||
|
// @flow
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import Button from 'component/button';
|
import Button from 'component/button';
|
||||||
import classnames from 'classnames';
|
|
||||||
import * as icons from 'constants/icons';
|
import * as icons from 'constants/icons';
|
||||||
|
|
||||||
class FileDownloadLink extends React.PureComponent {
|
type Props = {
|
||||||
componentWillMount() {
|
uri: string,
|
||||||
this.checkAvailability(this.props.uri);
|
downloading: boolean,
|
||||||
}
|
fileInfo: ?{
|
||||||
|
written_bytes: number,
|
||||||
componentWillReceiveProps(nextProps) {
|
total_bytes: number,
|
||||||
this.checkAvailability(nextProps.uri);
|
outpoint: number,
|
||||||
this.restartDownload(nextProps);
|
download_path: string,
|
||||||
}
|
completed: boolean,
|
||||||
|
},
|
||||||
restartDownload(props) {
|
loading: boolean,
|
||||||
const { downloading, fileInfo, uri, restartDownload } = props;
|
costInfo: ?{},
|
||||||
|
restartDownload: (string, number) => void,
|
||||||
|
openInShell: string => void,
|
||||||
|
purchaseUri: string => void,
|
||||||
|
doPause: () => void,
|
||||||
|
};
|
||||||
|
|
||||||
|
class FileDownloadLink extends React.PureComponent<Props> {
|
||||||
|
componentWillUpdate() {
|
||||||
|
const { downloading, fileInfo, uri, restartDownload } = this.props;
|
||||||
if (
|
if (
|
||||||
!downloading &&
|
!downloading &&
|
||||||
fileInfo &&
|
fileInfo &&
|
||||||
|
@ -27,12 +35,7 @@ class FileDownloadLink extends React.PureComponent {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
checkAvailability(uri) {
|
uri: ?string;
|
||||||
if (!this._uri || uri !== this._uri) {
|
|
||||||
this._uri = uri;
|
|
||||||
this.props.checkAvailability(uri);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const {
|
const {
|
||||||
|
@ -47,8 +50,10 @@ class FileDownloadLink extends React.PureComponent {
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
const openFile = () => {
|
const openFile = () => {
|
||||||
openInShell(fileInfo.download_path);
|
if (fileInfo) {
|
||||||
doPause();
|
openInShell(fileInfo.download_path);
|
||||||
|
doPause();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
if (loading || downloading) {
|
if (loading || downloading) {
|
||||||
|
@ -56,21 +61,11 @@ class FileDownloadLink extends React.PureComponent {
|
||||||
fileInfo && fileInfo.written_bytes
|
fileInfo && fileInfo.written_bytes
|
||||||
? fileInfo.written_bytes / fileInfo.total_bytes * 100
|
? fileInfo.written_bytes / fileInfo.total_bytes * 100
|
||||||
: 0;
|
: 0;
|
||||||
const label = fileInfo ? progress.toFixed(0) + __('% complete') : __('Connecting...');
|
const label = fileInfo
|
||||||
|
? __('Downloading: ') + progress.toFixed(0) + __('% complete')
|
||||||
|
: __('Connecting...');
|
||||||
|
|
||||||
return (
|
return <span className="file-download">{label}</span>;
|
||||||
<div className="file-download btn__content">
|
|
||||||
<div
|
|
||||||
className={classnames('file-download__overlay', {
|
|
||||||
btn__content: !!progress,
|
|
||||||
})}
|
|
||||||
style={{ width: `${progress}%` }}
|
|
||||||
>
|
|
||||||
{label}
|
|
||||||
</div>
|
|
||||||
{label}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
} else if (fileInfo === null && !downloading) {
|
} else if (fileInfo === null && !downloading) {
|
||||||
if (!costInfo) {
|
if (!costInfo) {
|
||||||
return null;
|
return null;
|
||||||
|
@ -78,9 +73,10 @@ class FileDownloadLink extends React.PureComponent {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Button
|
<Button
|
||||||
className="btn--file-actions"
|
button="alt"
|
||||||
description={__('Download')}
|
label={__('Download')}
|
||||||
icon={icons.DOWNLOAD}
|
icon={icons.DOWNLOAD}
|
||||||
|
iconColor="purple"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
purchaseUri(uri);
|
purchaseUri(uri);
|
||||||
}}
|
}}
|
||||||
|
@ -89,8 +85,9 @@ class FileDownloadLink extends React.PureComponent {
|
||||||
} else if (fileInfo && fileInfo.download_path) {
|
} else if (fileInfo && fileInfo.download_path) {
|
||||||
return (
|
return (
|
||||||
<Button
|
<Button
|
||||||
className="btn--file-actions"
|
button="alt"
|
||||||
description={__('Open')}
|
iconColor="purple"
|
||||||
|
label={__('Open File')}
|
||||||
icon={icons.OPEN}
|
icon={icons.OPEN}
|
||||||
onClick={() => openFile()}
|
onClick={() => openFile()}
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -8,6 +8,7 @@ type FileInfo = {
|
||||||
name: string,
|
name: string,
|
||||||
channelName: ?string,
|
channelName: ?string,
|
||||||
pending?: boolean,
|
pending?: boolean,
|
||||||
|
channel_claim_id: string,
|
||||||
value?: {
|
value?: {
|
||||||
publisherSignature: {
|
publisherSignature: {
|
||||||
certificateId: string,
|
certificateId: string,
|
||||||
|
@ -139,6 +140,8 @@ class FileList extends React.PureComponent<Props, State> {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sortFunctions: {};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { fileInfos, hideFilter, checkPending } = this.props;
|
const { fileInfos, hideFilter, checkPending } = this.props;
|
||||||
const { sortBy } = this.state;
|
const { sortBy } = this.state;
|
||||||
|
@ -149,27 +152,14 @@ class FileList extends React.PureComponent<Props, State> {
|
||||||
}
|
}
|
||||||
|
|
||||||
this.sortFunctions[sortBy](fileInfos).forEach(fileInfo => {
|
this.sortFunctions[sortBy](fileInfos).forEach(fileInfo => {
|
||||||
const {
|
const { name: claimName, claim_name: claimNameDownloaded, claim_id: claimId } = fileInfo;
|
||||||
channel_name: channelName,
|
|
||||||
name: claimName,
|
|
||||||
claim_name: claimNameDownloaded,
|
|
||||||
claim_id: claimId,
|
|
||||||
} = fileInfo;
|
|
||||||
const uriParams = {};
|
const uriParams = {};
|
||||||
|
|
||||||
// This is unfortunate
|
// This is unfortunate
|
||||||
// https://github.com/lbryio/lbry/issues/1159
|
// https://github.com/lbryio/lbry/issues/1159
|
||||||
const name = claimName || claimNameDownloaded;
|
const name = claimName || claimNameDownloaded;
|
||||||
|
uriParams.contentName = name;
|
||||||
if (channelName) {
|
uriParams.claimId = claimId;
|
||||||
uriParams.channelName = channelName;
|
|
||||||
uriParams.contentName = name;
|
|
||||||
uriParams.claimId = this.getChannelSignature(fileInfo);
|
|
||||||
} else {
|
|
||||||
uriParams.claimId = claimId;
|
|
||||||
uriParams.claimName = name;
|
|
||||||
}
|
|
||||||
|
|
||||||
const uri = buildURI(uriParams);
|
const uri = buildURI(uriParams);
|
||||||
|
|
||||||
content.push(<FileCard key={uri} uri={uri} checkPending={checkPending} />);
|
content.push(<FileCard key={uri} uri={uri} checkPending={checkPending} />);
|
||||||
|
|
|
@ -58,8 +58,8 @@ class FileListSearch extends React.PureComponent<Props> {
|
||||||
return (
|
return (
|
||||||
query && (
|
query && (
|
||||||
<div className="search__results">
|
<div className="search__results">
|
||||||
<div className="search-result__column">
|
<div className="search-result__row">
|
||||||
<div className="file-list__header">{__('Files')}</div>
|
<div className="file-list__header">{__('Content')}</div>
|
||||||
{!isSearching &&
|
{!isSearching &&
|
||||||
(fileResults.length ? (
|
(fileResults.length ? (
|
||||||
fileResults.map(uri => <FileTile key={uri} uri={uri} />)
|
fileResults.map(uri => <FileTile key={uri} uri={uri} />)
|
||||||
|
@ -68,7 +68,7 @@ class FileListSearch extends React.PureComponent<Props> {
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="search-result__column">
|
<div className="search-result__row">
|
||||||
<div className="file-list__header">{__('Channels')}</div>
|
<div className="file-list__header">{__('Channels')}</div>
|
||||||
{!isSearching &&
|
{!isSearching &&
|
||||||
(channelResults.length ? (
|
(channelResults.length ? (
|
||||||
|
@ -78,10 +78,10 @@ class FileListSearch extends React.PureComponent<Props> {
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="search-result__column">
|
<div className="search-result__row">
|
||||||
<div className="file-list__header">{__('Your downloads')}</div>
|
<div className="file-list__header">{__('Your downloads')}</div>
|
||||||
{downloadUris && downloadUris.length ? (
|
{downloadUris && downloadUris.length ? (
|
||||||
downloadUris.map(uri => <FileTile test key={uri} uri={uri} />)
|
downloadUris.map(uri => <FileTile hideNoResult key={uri} uri={uri} />)
|
||||||
) : (
|
) : (
|
||||||
<NoResults />
|
<NoResults />
|
||||||
)}
|
)}
|
||||||
|
|
|
@ -35,20 +35,14 @@ class FilePrice extends React.PureComponent<Props> {
|
||||||
render() {
|
render() {
|
||||||
const { costInfo, showFullPrice } = this.props;
|
const { costInfo, showFullPrice } = this.props;
|
||||||
|
|
||||||
const isEstimate = costInfo ? !costInfo.includesData : false;
|
return costInfo ? (
|
||||||
|
|
||||||
if (!costInfo) {
|
|
||||||
return <span className="credit-amount">PRICE</span>;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<CreditAmount
|
<CreditAmount
|
||||||
amount={costInfo.cost}
|
amount={costInfo.cost}
|
||||||
isEstimate={isEstimate}
|
isEstimate={!costInfo.includesData}
|
||||||
showFree
|
showFree
|
||||||
showFullPrice={showFullPrice}
|
showFullPrice={showFullPrice}
|
||||||
/>
|
/>
|
||||||
);
|
) : null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,12 +1,13 @@
|
||||||
// @flow
|
// @flow
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import * as icons from 'constants/icons';
|
import * as icons from 'constants/icons';
|
||||||
import { normalizeURI, isURIClaimable, parseURI } from 'lbry-redux';
|
import { normalizeURI, parseURI } from 'lbry-redux';
|
||||||
import CardMedia from 'component/cardMedia';
|
import CardMedia from 'component/cardMedia';
|
||||||
import TruncatedText from 'component/common/truncated-text';
|
import TruncatedText from 'component/common/truncated-text';
|
||||||
import Icon from 'component/common/icon';
|
import Icon from 'component/common/icon';
|
||||||
import Button from 'component/button';
|
import Button from 'component/button';
|
||||||
import classnames from 'classnames';
|
import classnames from 'classnames';
|
||||||
|
import FilePrice from 'component/filePrice';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
fullWidth: boolean, // removes the max-width css
|
fullWidth: boolean, // removes the max-width css
|
||||||
|
@ -21,11 +22,15 @@ type Props = {
|
||||||
channel_name: string,
|
channel_name: string,
|
||||||
claim_id: string,
|
claim_id: string,
|
||||||
},
|
},
|
||||||
metadata: {},
|
metadata: ?{
|
||||||
|
title: ?string,
|
||||||
|
thumbnail: ?string,
|
||||||
|
},
|
||||||
resolveUri: string => void,
|
resolveUri: string => void,
|
||||||
navigate: (string, ?{}) => void,
|
navigate: (string, ?{}) => void,
|
||||||
clearPublish: () => void,
|
clearPublish: () => void,
|
||||||
updatePublishForm: () => void,
|
updatePublishForm: ({}) => void,
|
||||||
|
hideNoResult: boolean, // don't show the tile if there is no claim at this uri
|
||||||
};
|
};
|
||||||
|
|
||||||
class FileTile extends React.PureComponent<Props> {
|
class FileTile extends React.PureComponent<Props> {
|
||||||
|
@ -58,10 +63,12 @@ class FileTile extends React.PureComponent<Props> {
|
||||||
isDownloaded,
|
isDownloaded,
|
||||||
clearPublish,
|
clearPublish,
|
||||||
updatePublishForm,
|
updatePublishForm,
|
||||||
|
hideNoResult,
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
const uri = normalizeURI(this.props.uri);
|
const uri = normalizeURI(this.props.uri);
|
||||||
const isClaimed = !!claim;
|
const isClaimed = !!claim;
|
||||||
|
const description = isClaimed && metadata && metadata.description ? metadata.description : '';
|
||||||
const title =
|
const title =
|
||||||
isClaimed && metadata && metadata.title ? metadata.title : parseURI(uri).contentName;
|
isClaimed && metadata && metadata.title ? metadata.title : parseURI(uri).contentName;
|
||||||
const thumbnail = metadata && metadata.thumbnail ? metadata.thumbnail : null;
|
const thumbnail = metadata && metadata.thumbnail ? metadata.thumbnail : null;
|
||||||
|
@ -76,7 +83,7 @@ class FileTile extends React.PureComponent<Props> {
|
||||||
channel = claim.channel_name;
|
channel = claim.channel_name;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return !name && hideNoResult ? null : (
|
||||||
<section
|
<section
|
||||||
className={classnames('file-tile card--link', {
|
className={classnames('file-tile card--link', {
|
||||||
'file-tile--fullwidth': fullWidth,
|
'file-tile--fullwidth': fullWidth,
|
||||||
|
@ -99,6 +106,12 @@ class FileTile extends React.PureComponent<Props> {
|
||||||
{isRewardContent && <Icon icon={icons.FEATURED} />}
|
{isRewardContent && <Icon icon={icons.FEATURED} />}
|
||||||
{showLocal && isDownloaded && <Icon icon={icons.LOCAL} />}
|
{showLocal && isDownloaded && <Icon icon={icons.LOCAL} />}
|
||||||
</div>
|
</div>
|
||||||
|
<div className="card__subtext card__subtext--small">
|
||||||
|
<TruncatedText lines={3}>{description}</TruncatedText>
|
||||||
|
</div>
|
||||||
|
<div className="card__subtitle-price">
|
||||||
|
<FilePrice uri={uri} />
|
||||||
|
</div>
|
||||||
{!name && (
|
{!name && (
|
||||||
<React.Fragment>
|
<React.Fragment>
|
||||||
{__('This location is unused.')}{' '}
|
{__('This location is unused.')}{' '}
|
||||||
|
|
|
@ -1,26 +1,17 @@
|
||||||
import React from 'react';
|
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import InviteNew from './view';
|
|
||||||
import {
|
import {
|
||||||
selectUserInvitesRemaining,
|
selectUserInvitesRemaining,
|
||||||
selectUserInviteNewIsPending,
|
selectUserInviteNewIsPending,
|
||||||
selectUserInviteNewErrorMessage,
|
selectUserInviteNewErrorMessage,
|
||||||
} from 'redux/selectors/user';
|
} from 'redux/selectors/user';
|
||||||
import rewards from 'rewards';
|
|
||||||
import { makeSelectRewardAmountByType } from 'redux/selectors/rewards';
|
|
||||||
|
|
||||||
import { doUserInviteNew } from 'redux/actions/user';
|
import { doUserInviteNew } from 'redux/actions/user';
|
||||||
|
import InviteNew from './view';
|
||||||
|
|
||||||
const select = state => {
|
const select = state => ({
|
||||||
const selectReward = makeSelectRewardAmountByType();
|
errorMessage: selectUserInviteNewErrorMessage(state),
|
||||||
|
invitesRemaining: selectUserInvitesRemaining(state),
|
||||||
return {
|
isPending: selectUserInviteNewIsPending(state),
|
||||||
errorMessage: selectUserInviteNewErrorMessage(state),
|
});
|
||||||
invitesRemaining: selectUserInvitesRemaining(state),
|
|
||||||
isPending: selectUserInviteNewIsPending(state),
|
|
||||||
rewardAmount: selectReward(state, { reward_type: rewards.TYPE_REFERRAL }),
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
const perform = dispatch => ({
|
const perform = dispatch => ({
|
||||||
inviteNew: email => dispatch(doUserInviteNew(email)),
|
inviteNew: email => dispatch(doUserInviteNew(email)),
|
||||||
|
|
|
@ -29,8 +29,7 @@ class FormInviteNew extends React.PureComponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { errorMessage, isPending, rewardAmount } = this.props;
|
const { errorMessage, isPending } = this.props;
|
||||||
const label = `${__('Get')} ${rewardAmount} LBC`;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Form onSubmit={this.handleSubmit}>
|
<Form onSubmit={this.handleSubmit}>
|
||||||
|
@ -49,7 +48,7 @@ class FormInviteNew extends React.PureComponent {
|
||||||
/>
|
/>
|
||||||
</FormRow>
|
</FormRow>
|
||||||
<div className="card__actions">
|
<div className="card__actions">
|
||||||
<Submit label={label} disabled={isPending} />
|
<Submit label="Invite" disabled={isPending} />
|
||||||
</div>
|
</div>
|
||||||
</Form>
|
</Form>
|
||||||
);
|
);
|
||||||
|
|
|
@ -10,6 +10,7 @@ import FileSelector from 'component/common/file-selector';
|
||||||
import { COPYRIGHT, OTHER } from 'constants/licenses';
|
import { COPYRIGHT, OTHER } from 'constants/licenses';
|
||||||
import { CHANNEL_NEW, CHANNEL_ANONYMOUS, MINIMUM_PUBLISH_BID } from 'constants/claim';
|
import { CHANNEL_NEW, CHANNEL_ANONYMOUS, MINIMUM_PUBLISH_BID } from 'constants/claim';
|
||||||
import * as icons from 'constants/icons';
|
import * as icons from 'constants/icons';
|
||||||
|
import type { Claim } from 'types/claim';
|
||||||
import BidHelpText from './internal/bid-help-text';
|
import BidHelpText from './internal/bid-help-text';
|
||||||
import LicenseType from './internal/license-type';
|
import LicenseType from './internal/license-type';
|
||||||
|
|
||||||
|
@ -36,14 +37,7 @@ type Props = {
|
||||||
nameError: ?string,
|
nameError: ?string,
|
||||||
isResolvingUri: boolean,
|
isResolvingUri: boolean,
|
||||||
winningBidForClaimUri: number,
|
winningBidForClaimUri: number,
|
||||||
myClaimForUri: ?{
|
myClaimForUri: ?Claim,
|
||||||
amount: number,
|
|
||||||
value: {
|
|
||||||
stream: {
|
|
||||||
source: { source: string },
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
licenseType: string,
|
licenseType: string,
|
||||||
otherLicenseDescription: ?string,
|
otherLicenseDescription: ?string,
|
||||||
licenseUrl: ?string,
|
licenseUrl: ?string,
|
||||||
|
@ -55,7 +49,7 @@ type Props = {
|
||||||
clearPublish: () => void,
|
clearPublish: () => void,
|
||||||
resolveUri: string => void,
|
resolveUri: string => void,
|
||||||
scrollToTop: () => void,
|
scrollToTop: () => void,
|
||||||
prepareEdit: ({}, uri) => void,
|
prepareEdit: ({}, string) => void,
|
||||||
};
|
};
|
||||||
|
|
||||||
class PublishForm extends React.PureComponent<Props> {
|
class PublishForm extends React.PureComponent<Props> {
|
||||||
|
@ -138,12 +132,12 @@ class PublishForm extends React.PureComponent<Props> {
|
||||||
|
|
||||||
handleChannelChange(channelName: string) {
|
handleChannelChange(channelName: string) {
|
||||||
const { name, updatePublishForm } = this.props;
|
const { name, updatePublishForm } = this.props;
|
||||||
|
const form = { channel: channelName };
|
||||||
|
|
||||||
if (name) {
|
if (name) {
|
||||||
const uri = this.getNewUri(name, channelName);
|
form.uri = this.getNewUri(name, channelName);
|
||||||
updatePublishForm({ channel: channelName, uri });
|
|
||||||
} else {
|
|
||||||
updatePublishForm({ channel: channelName });
|
|
||||||
}
|
}
|
||||||
|
updatePublishForm(form);
|
||||||
}
|
}
|
||||||
|
|
||||||
handleBidChange(bid: number) {
|
handleBidChange(bid: number) {
|
||||||
|
@ -183,7 +177,6 @@ class PublishForm extends React.PureComponent<Props> {
|
||||||
description,
|
description,
|
||||||
language,
|
language,
|
||||||
nsfw,
|
nsfw,
|
||||||
channel,
|
|
||||||
licenseType,
|
licenseType,
|
||||||
licenseUrl,
|
licenseUrl,
|
||||||
otherLicenseDescription,
|
otherLicenseDescription,
|
||||||
|
@ -193,6 +186,7 @@ class PublishForm extends React.PureComponent<Props> {
|
||||||
price,
|
price,
|
||||||
uri,
|
uri,
|
||||||
myClaimForUri,
|
myClaimForUri,
|
||||||
|
channel,
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
let publishingLicense;
|
let publishingLicense;
|
||||||
|
@ -217,7 +211,6 @@ class PublishForm extends React.PureComponent<Props> {
|
||||||
description,
|
description,
|
||||||
language,
|
language,
|
||||||
nsfw,
|
nsfw,
|
||||||
channel,
|
|
||||||
license: publishingLicense,
|
license: publishingLicense,
|
||||||
licenseUrl: publishingLicenseUrl,
|
licenseUrl: publishingLicenseUrl,
|
||||||
otherLicenseDescription,
|
otherLicenseDescription,
|
||||||
|
@ -226,6 +219,7 @@ class PublishForm extends React.PureComponent<Props> {
|
||||||
contentIsFree,
|
contentIsFree,
|
||||||
price,
|
price,
|
||||||
uri,
|
uri,
|
||||||
|
channel,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Editing a claim
|
// Editing a claim
|
||||||
|
@ -300,7 +294,13 @@ class PublishForm extends React.PureComponent<Props> {
|
||||||
const formDisabled = (!filePath && !editingURI) || publishing;
|
const formDisabled = (!filePath && !editingURI) || publishing;
|
||||||
const formValid = this.checkIsFormValid();
|
const formValid = this.checkIsFormValid();
|
||||||
|
|
||||||
const simpleUri = uri && uri.split('#')[0];
|
// The user could be linked from lbry://@channel... or lbry://claim-name...
|
||||||
|
// If a channel exists, we need to make sure it is added to the uri for proper edit handling
|
||||||
|
// If this isn't an edit, just use the pregenerated uri
|
||||||
|
const simpleUri = myClaimForUri
|
||||||
|
? buildURI({ channelName: myClaimForUri.channel_name, contentName: myClaimForUri.name })
|
||||||
|
: uri;
|
||||||
|
|
||||||
const isStillEditing = editingURI === simpleUri;
|
const isStillEditing = editingURI === simpleUri;
|
||||||
let submitLabel;
|
let submitLabel;
|
||||||
if (isStillEditing) {
|
if (isStillEditing) {
|
||||||
|
|
|
@ -16,7 +16,7 @@ const makeSelect = () => {
|
||||||
const select = (state, props) => ({
|
const select = (state, props) => ({
|
||||||
errorMessage: selectError(state, props),
|
errorMessage: selectError(state, props),
|
||||||
isPending: selectIsPending(state, props),
|
isPending: selectIsPending(state, props),
|
||||||
reward: selectReward(state, props),
|
reward: selectReward(state, props.reward_type),
|
||||||
});
|
});
|
||||||
|
|
||||||
return select;
|
return select;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { selectCurrentPage, selectCurrentParams } from 'lbry-redux';
|
import { selectCurrentPage, selectCurrentParams, doNotify } from 'lbry-redux';
|
||||||
import Router from './view';
|
import Router from './view';
|
||||||
|
|
||||||
const select = state => ({
|
const select = state => ({
|
||||||
|
@ -7,4 +7,4 @@ const select = state => ({
|
||||||
currentPage: selectCurrentPage(state),
|
currentPage: selectCurrentPage(state),
|
||||||
});
|
});
|
||||||
|
|
||||||
export default connect(select, null)(Router);
|
export default connect(select, { doNotify })(Router);
|
||||||
|
|
|
@ -17,17 +17,23 @@ import AuthPage from 'page/auth';
|
||||||
import InvitePage from 'page/invite';
|
import InvitePage from 'page/invite';
|
||||||
import BackupPage from 'page/backup';
|
import BackupPage from 'page/backup';
|
||||||
import SubscriptionsPage from 'page/subscriptions';
|
import SubscriptionsPage from 'page/subscriptions';
|
||||||
|
import SearchPage from 'page/search';
|
||||||
|
|
||||||
const route = (page, routesMap) => {
|
const route = (props, page, routesMap) => {
|
||||||
const component = routesMap[page];
|
const component = routesMap[page];
|
||||||
|
if (!component) {
|
||||||
return component || DiscoverPage;
|
props.doNotify({
|
||||||
|
message: __('Invalid page requested'),
|
||||||
|
displayType: ['snackbar'],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return component || routesMap.discover;
|
||||||
};
|
};
|
||||||
|
|
||||||
const Router = props => {
|
const Router = props => {
|
||||||
const { currentPage, params } = props;
|
const { currentPage, params } = props;
|
||||||
|
|
||||||
return route(currentPage, {
|
return route(props, currentPage, {
|
||||||
auth: <AuthPage params={params} />,
|
auth: <AuthPage params={params} />,
|
||||||
backup: <BackupPage params={params} />,
|
backup: <BackupPage params={params} />,
|
||||||
channel: <ChannelPage params={params} />,
|
channel: <ChannelPage params={params} />,
|
||||||
|
@ -46,6 +52,7 @@ const Router = props => {
|
||||||
show: <ShowPage {...params} />,
|
show: <ShowPage {...params} />,
|
||||||
wallet: <WalletPage params={params} />,
|
wallet: <WalletPage params={params} />,
|
||||||
subscriptions: <SubscriptionsPage params={params} />,
|
subscriptions: <SubscriptionsPage params={params} />,
|
||||||
|
search: <SearchPage {...params} />,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -37,8 +37,9 @@ export default (props: Props) => {
|
||||||
|
|
||||||
return channelName && uri ? (
|
return channelName && uri ? (
|
||||||
<Button
|
<Button
|
||||||
|
iconColor="red"
|
||||||
icon={isSubscribed ? undefined : icons.HEART}
|
icon={isSubscribed ? undefined : icons.HEART}
|
||||||
button={isSubscribed ? 'danger' : 'alt'}
|
button="alt"
|
||||||
label={subscriptionLabel}
|
label={subscriptionLabel}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
if (!subscriptions.length) {
|
if (!subscriptions.length) {
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
|
import { doNotify, MODALS } from 'lbry-redux';
|
||||||
import { doNavigate } from 'redux/actions/navigation';
|
import { doNavigate } from 'redux/actions/navigation';
|
||||||
import { doUserIdentityVerify } from 'redux/actions/user';
|
import { doUserIdentityVerify } from 'redux/actions/user';
|
||||||
import rewards from 'rewards';
|
import rewards from 'rewards';
|
||||||
|
@ -8,15 +9,14 @@ import {
|
||||||
selectIdentityVerifyErrorMessage,
|
selectIdentityVerifyErrorMessage,
|
||||||
} from 'redux/selectors/user';
|
} from 'redux/selectors/user';
|
||||||
import UserVerify from './view';
|
import UserVerify from './view';
|
||||||
import { doNotify, MODALS } from 'lbry-redux';
|
|
||||||
|
|
||||||
const select = (state, props) => {
|
const select = state => {
|
||||||
const selectReward = makeSelectRewardByType();
|
const selectReward = makeSelectRewardByType();
|
||||||
|
|
||||||
return {
|
return {
|
||||||
isPending: selectIdentityVerifyIsPending(state),
|
isPending: selectIdentityVerifyIsPending(state),
|
||||||
errorMessage: selectIdentityVerifyErrorMessage(state),
|
errorMessage: selectIdentityVerifyErrorMessage(state),
|
||||||
reward: selectReward(state, { reward_type: rewards.TYPE_NEW_USER }),
|
reward: selectReward(state, rewards.TYPE_NEW_USER),
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -12,11 +12,9 @@ import {
|
||||||
makeSelectFileInfoForUri,
|
makeSelectFileInfoForUri,
|
||||||
makeSelectLoadingForUri,
|
makeSelectLoadingForUri,
|
||||||
makeSelectDownloadingForUri,
|
makeSelectDownloadingForUri,
|
||||||
|
selectSearchBarFocused,
|
||||||
} from 'lbry-redux';
|
} from 'lbry-redux';
|
||||||
import {
|
import { makeSelectClientSetting, selectShowNsfw } from 'redux/selectors/settings';
|
||||||
makeSelectClientSetting,
|
|
||||||
selectShowNsfw
|
|
||||||
} from 'redux/selectors/settings';
|
|
||||||
import { selectMediaPaused, makeSelectMediaPositionForUri } from 'redux/selectors/media';
|
import { selectMediaPaused, makeSelectMediaPositionForUri } from 'redux/selectors/media';
|
||||||
import { selectPlayingUri } from 'redux/selectors/content';
|
import { selectPlayingUri } from 'redux/selectors/content';
|
||||||
import Video from './view';
|
import Video from './view';
|
||||||
|
@ -34,7 +32,8 @@ const select = (state, props) => ({
|
||||||
volume: selectVolume(state),
|
volume: selectVolume(state),
|
||||||
mediaPaused: selectMediaPaused(state),
|
mediaPaused: selectMediaPaused(state),
|
||||||
mediaPosition: makeSelectMediaPositionForUri(props.uri)(state),
|
mediaPosition: makeSelectMediaPositionForUri(props.uri)(state),
|
||||||
autoplay: makeSelectClientSetting(settings.AUTOPLAY)(state)
|
autoplay: makeSelectClientSetting(settings.AUTOPLAY)(state),
|
||||||
|
searchBarFocused: selectSearchBarFocused(state),
|
||||||
});
|
});
|
||||||
|
|
||||||
const perform = dispatch => ({
|
const perform = dispatch => ({
|
||||||
|
|
|
@ -3,41 +3,21 @@ import React from 'react';
|
||||||
import Button from 'component/button';
|
import Button from 'component/button';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
play: string => void,
|
play: () => void,
|
||||||
isLoading: boolean,
|
isLoading: boolean,
|
||||||
uri: string,
|
|
||||||
mediaType: string,
|
mediaType: string,
|
||||||
fileInfo: ?{},
|
fileInfo: ?{},
|
||||||
};
|
};
|
||||||
|
|
||||||
class VideoPlayButton extends React.PureComponent<Props> {
|
class VideoPlayButton extends React.PureComponent<Props> {
|
||||||
watch: () => void;
|
|
||||||
|
|
||||||
constructor() {
|
|
||||||
super();
|
|
||||||
this.watch = this.watch.bind(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
watch() {
|
|
||||||
this.props.play(this.props.uri);
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { fileInfo, mediaType, isLoading } = this.props;
|
const { fileInfo, mediaType, isLoading, play } = this.props;
|
||||||
const disabled = isLoading || fileInfo === undefined;
|
const disabled = isLoading || fileInfo === undefined;
|
||||||
const doesPlayback = ['audio', 'video'].indexOf(mediaType) !== -1;
|
const doesPlayback = ['audio', 'video'].indexOf(mediaType) !== -1;
|
||||||
const icon = doesPlayback ? 'Play' : 'Folder';
|
const icon = doesPlayback ? 'Play' : 'Folder';
|
||||||
const label = doesPlayback ? 'Play' : 'View';
|
const label = doesPlayback ? 'Play' : 'View';
|
||||||
|
|
||||||
return (
|
return <Button button="primary" disabled={disabled} label={label} icon={icon} onClick={play} />;
|
||||||
<Button
|
|
||||||
button="secondary"
|
|
||||||
disabled={disabled}
|
|
||||||
label={label}
|
|
||||||
icon={icon}
|
|
||||||
onClick={this.watch}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,6 +19,7 @@ class VideoPlayer extends React.PureComponent {
|
||||||
};
|
};
|
||||||
|
|
||||||
this.togglePlayListener = this.togglePlay.bind(this);
|
this.togglePlayListener = this.togglePlay.bind(this);
|
||||||
|
this.toggleFullScreenVideo = this.toggleFullScreen.bind(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillReceiveProps(nextProps) {
|
componentWillReceiveProps(nextProps) {
|
||||||
|
@ -77,6 +78,7 @@ class VideoPlayer extends React.PureComponent {
|
||||||
changeVolume(mediaElement.volume);
|
changeVolume(mediaElement.volume);
|
||||||
});
|
});
|
||||||
mediaElement.volume = volume;
|
mediaElement.volume = volume;
|
||||||
|
mediaElement.addEventListener('dblclick', this.toggleFullScreenVideo);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -112,6 +114,17 @@ class VideoPlayer extends React.PureComponent {
|
||||||
this.props.doPause();
|
this.props.doPause();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
toggleFullScreen(event) {
|
||||||
|
const mediaElement = this.media.children[0];
|
||||||
|
if (mediaElement) {
|
||||||
|
if (document.webkitIsFullScreen) {
|
||||||
|
document.webkitExitFullscreen();
|
||||||
|
} else {
|
||||||
|
mediaElement.webkitRequestFullScreen();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
togglePlay(event) {
|
togglePlay(event) {
|
||||||
// ignore all events except click and spacebar keydown, or input events in a form control
|
// ignore all events except click and spacebar keydown, or input events in a form control
|
||||||
if (
|
if (
|
||||||
|
|
|
@ -7,6 +7,8 @@ import VideoPlayer from './internal/player';
|
||||||
import VideoPlayButton from './internal/play-button';
|
import VideoPlayButton from './internal/play-button';
|
||||||
import LoadingScreen from './internal/loading-screen';
|
import LoadingScreen from './internal/loading-screen';
|
||||||
|
|
||||||
|
const SPACE_BAR_KEYCODE = 32;
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
cancelPlay: () => void,
|
cancelPlay: () => void,
|
||||||
fileInfo: {
|
fileInfo: {
|
||||||
|
@ -37,11 +39,20 @@ type Props = {
|
||||||
className: ?string,
|
className: ?string,
|
||||||
obscureNsfw: boolean,
|
obscureNsfw: boolean,
|
||||||
play: string => void,
|
play: string => void,
|
||||||
|
searchBarFocused: boolean,
|
||||||
};
|
};
|
||||||
|
|
||||||
class Video extends React.PureComponent<Props> {
|
class Video extends React.PureComponent<Props> {
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
|
||||||
|
(this: any).playContent = this.playContent.bind(this);
|
||||||
|
(this: any).handleKeyDown = this.handleKeyDown.bind(this);
|
||||||
|
}
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
this.handleAutoplay(this.props);
|
this.handleAutoplay(this.props);
|
||||||
|
window.addEventListener('keydown', this.handleKeyDown);
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillReceiveProps(nextProps: Props) {
|
componentWillReceiveProps(nextProps: Props) {
|
||||||
|
@ -57,10 +68,29 @@ class Video extends React.PureComponent<Props> {
|
||||||
|
|
||||||
componentWillUnmount() {
|
componentWillUnmount() {
|
||||||
this.props.cancelPlay();
|
this.props.cancelPlay();
|
||||||
|
window.removeEventListener('keydown', this.handleKeyDown);
|
||||||
}
|
}
|
||||||
|
|
||||||
handleAutoplay(props: Props) {
|
handleKeyDown(event: SyntheticKeyboardEvent<*>) {
|
||||||
const { autoplay, playingUri, fileInfo, costInfo, isDownloading, uri, load, play, metadata } = props;
|
const { searchBarFocused } = this.props;
|
||||||
|
if (!searchBarFocused && event.keyCode === SPACE_BAR_KEYCODE) {
|
||||||
|
event.preventDefault(); // prevent page scroll
|
||||||
|
this.playContent();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
handleAutoplay = (props: Props) => {
|
||||||
|
const {
|
||||||
|
autoplay,
|
||||||
|
playingUri,
|
||||||
|
fileInfo,
|
||||||
|
costInfo,
|
||||||
|
isDownloading,
|
||||||
|
uri,
|
||||||
|
load,
|
||||||
|
play,
|
||||||
|
metadata,
|
||||||
|
} = props;
|
||||||
|
|
||||||
const playable = autoplay && playingUri !== uri && metadata && !metadata.nsfw;
|
const playable = autoplay && playingUri !== uri && metadata && !metadata.nsfw;
|
||||||
|
|
||||||
|
@ -70,7 +100,7 @@ class Video extends React.PureComponent<Props> {
|
||||||
} else if (playable && fileInfo && fileInfo.blobs_completed > 0) {
|
} else if (playable && fileInfo && fileInfo.blobs_completed > 0) {
|
||||||
play(uri);
|
play(uri);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
isMediaSame(nextProps: Props) {
|
isMediaSame(nextProps: Props) {
|
||||||
return (
|
return (
|
||||||
|
@ -80,6 +110,11 @@ class Video extends React.PureComponent<Props> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
playContent() {
|
||||||
|
const { play, uri } = this.props;
|
||||||
|
play(uri);
|
||||||
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const {
|
const {
|
||||||
metadata,
|
metadata,
|
||||||
|
@ -99,7 +134,6 @@ class Video extends React.PureComponent<Props> {
|
||||||
mediaPosition,
|
mediaPosition,
|
||||||
className,
|
className,
|
||||||
obscureNsfw,
|
obscureNsfw,
|
||||||
play,
|
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
const isPlaying = playingUri === uri;
|
const isPlaying = playingUri === uri;
|
||||||
|
@ -154,9 +188,17 @@ class Video extends React.PureComponent<Props> {
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{!isPlaying && (
|
{!isPlaying && (
|
||||||
<div className={layoverClass} style={layoverStyle}>
|
<div
|
||||||
|
role="button"
|
||||||
|
onClick={this.playContent}
|
||||||
|
className={layoverClass}
|
||||||
|
style={layoverStyle}
|
||||||
|
>
|
||||||
<VideoPlayButton
|
<VideoPlayButton
|
||||||
play={play}
|
play={e => {
|
||||||
|
e.stopPropagation();
|
||||||
|
this.playContent();
|
||||||
|
}}
|
||||||
fileInfo={fileInfo}
|
fileInfo={fileInfo}
|
||||||
uri={uri}
|
uri={uri}
|
||||||
isLoading={isLoading}
|
isLoading={isLoading}
|
||||||
|
|
3
src/renderer/component/viewOnWebButton/index.js
Normal file
3
src/renderer/component/viewOnWebButton/index.js
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
import ViewOnWebButton from './view';
|
||||||
|
|
||||||
|
export default ViewOnWebButton;
|
21
src/renderer/component/viewOnWebButton/view.jsx
Normal file
21
src/renderer/component/viewOnWebButton/view.jsx
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
// @flow
|
||||||
|
import React from 'react';
|
||||||
|
import * as icons from 'constants/icons';
|
||||||
|
import Button from 'component/button';
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
uri: ?string,
|
||||||
|
};
|
||||||
|
|
||||||
|
export default (props: Props) => {
|
||||||
|
const { uri } = props;
|
||||||
|
|
||||||
|
return uri ? (
|
||||||
|
<Button
|
||||||
|
iconRight={icons.GLOBE}
|
||||||
|
button="alt"
|
||||||
|
label={__('View on Web')}
|
||||||
|
href={`http://spee.ch/${uri}`}
|
||||||
|
/>
|
||||||
|
) : null;
|
||||||
|
};
|
|
@ -1,9 +1,9 @@
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { doSendDraftTransaction, selectBalance } from 'lbry-redux';
|
import { selectBalance, doNotify } from 'lbry-redux';
|
||||||
import WalletSend from './view';
|
import WalletSend from './view';
|
||||||
|
|
||||||
const perform = dispatch => ({
|
const perform = dispatch => ({
|
||||||
sendToAddress: (address, amount) => dispatch(doSendDraftTransaction(address, amount)),
|
openModal: (modal, props) => dispatch(doNotify(modal, props)),
|
||||||
});
|
});
|
||||||
|
|
||||||
const select = state => ({
|
const select = state => ({
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
// @flow
|
// @flow
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import { MODALS } from 'lbry-redux';
|
||||||
import Button from 'component/button';
|
import Button from 'component/button';
|
||||||
import { Form, FormRow, FormField } from 'component/common/form';
|
import { Form, FormRow, FormField } from 'component/common/form';
|
||||||
import { Formik } from 'formik';
|
import { Formik } from 'formik';
|
||||||
|
@ -11,7 +12,7 @@ type DraftTransaction = {
|
||||||
};
|
};
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
sendToAddress: (string, number) => void,
|
openModal: ({ id: string }, { address: string, amount: number }) => void,
|
||||||
balance: number,
|
balance: number,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -23,10 +24,12 @@ class WalletSend extends React.PureComponent<Props> {
|
||||||
}
|
}
|
||||||
|
|
||||||
handleSubmit(values: DraftTransaction) {
|
handleSubmit(values: DraftTransaction) {
|
||||||
const { sendToAddress } = this.props;
|
const { openModal } = this.props;
|
||||||
const { address, amount } = values;
|
const { address, amount } = values;
|
||||||
if (amount && address) {
|
if (amount && address) {
|
||||||
sendToAddress(address, amount);
|
const notificationId = { id: MODALS.CONFIRM_TRANSACTION };
|
||||||
|
const modalProps = { address, amount };
|
||||||
|
openModal(notificationId, modalProps);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,7 @@ import {
|
||||||
makeSelectTitleForUri,
|
makeSelectTitleForUri,
|
||||||
makeSelectClaimForUri,
|
makeSelectClaimForUri,
|
||||||
selectIsSendingSupport,
|
selectIsSendingSupport,
|
||||||
|
selectBalance,
|
||||||
} from 'lbry-redux';
|
} from 'lbry-redux';
|
||||||
import WalletSendTip from './view';
|
import WalletSendTip from './view';
|
||||||
|
|
||||||
|
@ -11,6 +12,7 @@ const select = (state, props) => ({
|
||||||
isPending: selectIsSendingSupport(state),
|
isPending: selectIsSendingSupport(state),
|
||||||
title: makeSelectTitleForUri(props.uri)(state),
|
title: makeSelectTitleForUri(props.uri)(state),
|
||||||
claim: makeSelectClaimForUri(props.uri)(state),
|
claim: makeSelectClaimForUri(props.uri)(state),
|
||||||
|
balance: selectBalance(state),
|
||||||
});
|
});
|
||||||
|
|
||||||
const perform = dispatch => ({
|
const perform = dispatch => ({
|
||||||
|
|
|
@ -14,6 +14,7 @@ type Props = {
|
||||||
sendSupport: (number, string, string) => void,
|
sendSupport: (number, string, string) => void,
|
||||||
onCancel: () => void,
|
onCancel: () => void,
|
||||||
sendTipCallback?: () => void,
|
sendTipCallback?: () => void,
|
||||||
|
balance: number,
|
||||||
};
|
};
|
||||||
|
|
||||||
type State = {
|
type State = {
|
||||||
|
@ -51,7 +52,8 @@ class WalletSendTip extends React.PureComponent<Props, State> {
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { title, errorMessage, isPending, uri, onCancel } = this.props;
|
const { title, errorMessage, isPending, uri, onCancel, balance } = this.props;
|
||||||
|
const { amount } = this.state;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
|
@ -82,7 +84,7 @@ class WalletSendTip extends React.PureComponent<Props, State> {
|
||||||
<Button
|
<Button
|
||||||
button="primary"
|
button="primary"
|
||||||
label={__('Send')}
|
label={__('Send')}
|
||||||
disabled={isPending}
|
disabled={isPending || amount <= 0 || amount > balance}
|
||||||
onClick={this.handleSendButtonClicked}
|
onClick={this.handleSendButtonClicked}
|
||||||
/>
|
/>
|
||||||
<Button button="alt" label={__('Cancel')} onClick={onCancel} navigateParams={{ uri }} />
|
<Button button="alt" label={__('Cancel')} onClick={onCancel} navigateParams={{ uri }} />
|
||||||
|
|
|
@ -5,6 +5,9 @@ import {
|
||||||
doUpdateSearchQuery,
|
doUpdateSearchQuery,
|
||||||
doNotify,
|
doNotify,
|
||||||
MODALS,
|
MODALS,
|
||||||
|
doFocusSearchInput,
|
||||||
|
doBlurSearchInput,
|
||||||
|
doSearch,
|
||||||
} from 'lbry-redux';
|
} from 'lbry-redux';
|
||||||
import { doNavigate } from 'redux/actions/navigation';
|
import { doNavigate } from 'redux/actions/navigation';
|
||||||
import Wunderbar from './view';
|
import Wunderbar from './view';
|
||||||
|
@ -25,11 +28,13 @@ const select = state => {
|
||||||
|
|
||||||
const perform = dispatch => ({
|
const perform = dispatch => ({
|
||||||
onSearch: query => {
|
onSearch: query => {
|
||||||
dispatch(doUpdateSearchQuery(query));
|
dispatch(doSearch(query));
|
||||||
dispatch(doNotify({ id: MODALS.SEARCH }));
|
dispatch(doNavigate(`/search`, { query }));
|
||||||
},
|
},
|
||||||
onSubmit: (uri, extraParams) => dispatch(doNavigate('/show', { uri, ...extraParams })),
|
onSubmit: (uri, extraParams) => dispatch(doNavigate('/show', { uri, ...extraParams })),
|
||||||
updateSearchQuery: query => dispatch(doUpdateSearchQuery(query)),
|
updateSearchQuery: query => dispatch(doUpdateSearchQuery(query)),
|
||||||
|
doFocus: () => dispatch(doFocusSearchInput()),
|
||||||
|
doBlur: () => dispatch(doBlurSearchInput()),
|
||||||
});
|
});
|
||||||
|
|
||||||
export default connect(select, perform)(Wunderbar);
|
export default connect(select, perform)(Wunderbar);
|
||||||
|
|
|
@ -445,6 +445,10 @@ export default class Autocomplete extends React.Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
renderMenu() {
|
renderMenu() {
|
||||||
|
if (!this.props.value) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
const items = this.getFilteredItems(this.props).map((item, index) => {
|
const items = this.getFilteredItems(this.props).map((item, index) => {
|
||||||
const element = this.props.renderItem(item, this.state.highlightedIndex === index, {
|
const element = this.props.renderItem(item, this.state.highlightedIndex === index, {
|
||||||
cursor: 'default',
|
cursor: 'default',
|
||||||
|
|
|
@ -13,6 +13,8 @@ type Props = {
|
||||||
onSubmit: (string, {}) => void,
|
onSubmit: (string, {}) => void,
|
||||||
wunderbarValue: ?string,
|
wunderbarValue: ?string,
|
||||||
suggestions: Array<string>,
|
suggestions: Array<string>,
|
||||||
|
doFocus: () => void,
|
||||||
|
doBlur: () => void,
|
||||||
};
|
};
|
||||||
|
|
||||||
class WunderBar extends React.PureComponent<Props> {
|
class WunderBar extends React.PureComponent<Props> {
|
||||||
|
@ -83,7 +85,7 @@ class WunderBar extends React.PureComponent<Props> {
|
||||||
input: ?HTMLInputElement;
|
input: ?HTMLInputElement;
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { wunderbarValue, suggestions } = this.props;
|
const { wunderbarValue, suggestions, doFocus, doBlur } = this.props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="wunderbar">
|
<div className="wunderbar">
|
||||||
|
@ -96,6 +98,10 @@ class WunderBar extends React.PureComponent<Props> {
|
||||||
getItemValue={item => item.value}
|
getItemValue={item => item.value}
|
||||||
onChange={this.handleChange}
|
onChange={this.handleChange}
|
||||||
onSelect={this.handleSubmit}
|
onSelect={this.handleSubmit}
|
||||||
|
inputProps={{
|
||||||
|
onFocus: doFocus,
|
||||||
|
onBlur: doBlur,
|
||||||
|
}}
|
||||||
renderInput={props => (
|
renderInput={props => (
|
||||||
<input
|
<input
|
||||||
{...props}
|
{...props}
|
||||||
|
|
|
@ -25,3 +25,4 @@ export const CHECK = 'CheckCircle';
|
||||||
export const HEART = 'Heart';
|
export const HEART = 'Heart';
|
||||||
export const UNLOCK = 'Unlock';
|
export const UNLOCK = 'Unlock';
|
||||||
export const CHECK_SIMPLE = 'Check';
|
export const CHECK_SIMPLE = 'Check';
|
||||||
|
export const GLOBE = 'Globe';
|
||||||
|
|
|
@ -8,7 +8,7 @@ import React from 'react';
|
||||||
import ReactDOM from 'react-dom';
|
import ReactDOM from 'react-dom';
|
||||||
import { Provider } from 'react-redux';
|
import { Provider } from 'react-redux';
|
||||||
import { doConditionalAuthNavigate, doDaemonReady, doAutoUpdate } from 'redux/actions/app';
|
import { doConditionalAuthNavigate, doDaemonReady, doAutoUpdate } from 'redux/actions/app';
|
||||||
import { doNotify, doBlackListedOutpointsSubscribe } from 'lbry-redux';
|
import { doNotify, doBlackListedOutpointsSubscribe, isURIValid } from 'lbry-redux';
|
||||||
import { doNavigate } from 'redux/actions/navigation';
|
import { doNavigate } from 'redux/actions/navigation';
|
||||||
import { doDownloadLanguages, doUpdateIsNightAsync } from 'redux/actions/settings';
|
import { doDownloadLanguages, doUpdateIsNightAsync } from 'redux/actions/settings';
|
||||||
import { doUserEmailVerify } from 'redux/actions/user';
|
import { doUserEmailVerify } from 'redux/actions/user';
|
||||||
|
@ -16,8 +16,10 @@ import 'scss/all.scss';
|
||||||
import store from 'store';
|
import store from 'store';
|
||||||
import app from './app';
|
import app from './app';
|
||||||
import analytics from './analytics';
|
import analytics from './analytics';
|
||||||
|
import doLogWarningConsoleMessage from './logWarningConsoleMessage';
|
||||||
|
|
||||||
const { autoUpdater } = remote.require('electron-updater');
|
const { autoUpdater } = remote.require('electron-updater');
|
||||||
|
const APPPAGEURL = 'lbry://?';
|
||||||
|
|
||||||
autoUpdater.logger = remote.require('electron-log');
|
autoUpdater.logger = remote.require('electron-log');
|
||||||
|
|
||||||
|
@ -41,8 +43,18 @@ ipcRenderer.on('open-uri-requested', (event, uri, newSession) => {
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
} else {
|
} else if (uri.startsWith(APPPAGEURL)) {
|
||||||
|
const navpage = uri.replace(APPPAGEURL, '').toLowerCase();
|
||||||
|
app.store.dispatch(doNavigate(`/${navpage}`));
|
||||||
|
} else if (isURIValid(uri)) {
|
||||||
app.store.dispatch(doNavigate('/show', { uri }));
|
app.store.dispatch(doNavigate('/show', { uri }));
|
||||||
|
} else {
|
||||||
|
app.store.dispatch(
|
||||||
|
doNotify({
|
||||||
|
message: __('Invalid LBRY URL requested'),
|
||||||
|
displayType: ['snackbar'],
|
||||||
|
})
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -61,6 +73,11 @@ ipcRenderer.on('window-is-focused', () => {
|
||||||
dock.setBadge('');
|
dock.setBadge('');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
ipcRenderer.on('devtools-is-opened', () => {
|
||||||
|
const logOnDevelopment = false;
|
||||||
|
doLogWarningConsoleMessage(logOnDevelopment);
|
||||||
|
});
|
||||||
|
|
||||||
document.addEventListener('dragover', event => {
|
document.addEventListener('dragover', event => {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
});
|
});
|
||||||
|
|
34
src/renderer/logWarningConsoleMessage.js
Normal file
34
src/renderer/logWarningConsoleMessage.js
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
import isDev from 'electron-is-dev';
|
||||||
|
|
||||||
|
export default function doLogWarningConsoleMessage(activeOnDev = false) {
|
||||||
|
if (isDev && !activeOnDev) return;
|
||||||
|
const style = {
|
||||||
|
redTitle:
|
||||||
|
'color: red; font-size: 50px; text-shadow: -1px 0 black, 0 1px black, 1px 0 black, 0 -1px black;, font-weight: bold;',
|
||||||
|
normalText: 'font-size: 24px;',
|
||||||
|
redText:
|
||||||
|
'color: red; text-shadow: -1px 0 black, 0 1px black, 1px 0 black, 0 -1px black; font-size: 24px;',
|
||||||
|
};
|
||||||
|
console.clear();
|
||||||
|
console.log('%cScam alert!', style.redTitle);
|
||||||
|
|
||||||
|
console.log(
|
||||||
|
'%cIf someone told you to copy / paste something here you have a chance of being scammed.',
|
||||||
|
style.normalText
|
||||||
|
);
|
||||||
|
|
||||||
|
console.log(
|
||||||
|
'%cPasting anything in here could give attackers access to your LBC credits or wallet.',
|
||||||
|
style.normalText
|
||||||
|
);
|
||||||
|
|
||||||
|
console.log(
|
||||||
|
"%cIf you don't understand what you are doing here, please close this window and keep your LBC credits/wallet safe.",
|
||||||
|
style.redText
|
||||||
|
);
|
||||||
|
|
||||||
|
console.log(
|
||||||
|
'%cIf you do understand exactly what you are doing, you should come work with us https://lbry.io/join-us',
|
||||||
|
style.normalText
|
||||||
|
);
|
||||||
|
}
|
|
@ -56,7 +56,7 @@ export class Modal extends React.PureComponent<ModalProps> {
|
||||||
return (
|
return (
|
||||||
<ReactModal
|
<ReactModal
|
||||||
{...modalProps}
|
{...modalProps}
|
||||||
onCloseRequested={onAborted || onConfirmed}
|
onRequestClose={onAborted || onConfirmed}
|
||||||
className={classnames(className, {
|
className={classnames(className, {
|
||||||
modal: !fullScreen,
|
modal: !fullScreen,
|
||||||
'modal--fullscreen': fullScreen,
|
'modal--fullscreen': fullScreen,
|
||||||
|
|
|
@ -3,6 +3,12 @@ import FilePrice from 'component/filePrice';
|
||||||
import { Modal } from 'modal/modal';
|
import { Modal } from 'modal/modal';
|
||||||
|
|
||||||
class ModalAffirmPurchase extends React.PureComponent {
|
class ModalAffirmPurchase extends React.PureComponent {
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this.onAffirmPurchase = this.onAffirmPurchase.bind(this);
|
||||||
|
}
|
||||||
|
|
||||||
onAffirmPurchase() {
|
onAffirmPurchase() {
|
||||||
this.props.closeModal();
|
this.props.closeModal();
|
||||||
this.props.loadVideo(this.props.uri);
|
this.props.loadVideo(this.props.uri);
|
||||||
|
@ -20,7 +26,7 @@ class ModalAffirmPurchase extends React.PureComponent {
|
||||||
type="confirm"
|
type="confirm"
|
||||||
isOpen
|
isOpen
|
||||||
contentLabel={__('Confirm Purchase')}
|
contentLabel={__('Confirm Purchase')}
|
||||||
onConfirmed={this.onAffirmPurchase.bind(this)}
|
onConfirmed={this.onAffirmPurchase}
|
||||||
onAborted={cancelPurchase}
|
onAborted={cancelPurchase}
|
||||||
>
|
>
|
||||||
{__('This will purchase')} <strong>{title}</strong> {__('for')}{' '}
|
{__('This will purchase')} <strong>{title}</strong> {__('for')}{' '}
|
||||||
|
|
10
src/renderer/modal/modalConfirmTransaction/index.js
Normal file
10
src/renderer/modal/modalConfirmTransaction/index.js
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
import { connect } from 'react-redux';
|
||||||
|
import { doHideNotification, doSendDraftTransaction } from 'lbry-redux';
|
||||||
|
import ModalConfirmTransaction from './view';
|
||||||
|
|
||||||
|
const perform = dispatch => ({
|
||||||
|
closeModal: () => dispatch(doHideNotification()),
|
||||||
|
sendToAddress: (address, amount) => dispatch(doSendDraftTransaction(address, amount)),
|
||||||
|
});
|
||||||
|
|
||||||
|
export default connect(null, perform)(ModalConfirmTransaction);
|
44
src/renderer/modal/modalConfirmTransaction/view.jsx
Normal file
44
src/renderer/modal/modalConfirmTransaction/view.jsx
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
// @flow
|
||||||
|
import React from 'react';
|
||||||
|
import { Modal } from 'modal/modal';
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
address: string,
|
||||||
|
amount: number,
|
||||||
|
closeModal: () => void,
|
||||||
|
sendToAddress: (string, number) => void,
|
||||||
|
};
|
||||||
|
|
||||||
|
class ModalConfirmTransaction extends React.PureComponent<Props> {
|
||||||
|
onConfirmed() {
|
||||||
|
const { closeModal, sendToAddress, amount, address } = this.props;
|
||||||
|
sendToAddress(address, amount);
|
||||||
|
closeModal();
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { amount, address, closeModal } = this.props;
|
||||||
|
return (
|
||||||
|
<Modal
|
||||||
|
isOpen
|
||||||
|
contentLabel={__('Confirm Transaction')}
|
||||||
|
type="confirm"
|
||||||
|
confirmButtonLabel={__('Continue')}
|
||||||
|
onConfirmed={() => this.onConfirmed()}
|
||||||
|
onAborted={closeModal}
|
||||||
|
>
|
||||||
|
<p>{__('Are you sure you want to ')}</p>
|
||||||
|
<h1>
|
||||||
|
{__('send ')} {amount} LBC
|
||||||
|
</h1>
|
||||||
|
<p>{__('Sending: ')}</p>
|
||||||
|
<blockquote>{amount} LBC</blockquote>
|
||||||
|
<p>{__('To address: ')}</p>
|
||||||
|
<blockquote>{address}</blockquote>
|
||||||
|
<p>{__('Once the transaction is sent, it cannot be reversed.')}</p>
|
||||||
|
</Modal>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ModalConfirmTransaction;
|
|
@ -1,12 +1,18 @@
|
||||||
// I'll come back to this
|
// @flow
|
||||||
/* esline-disable */
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Modal } from 'modal/modal';
|
import { Modal } from 'modal/modal';
|
||||||
import CurrencySymbol from 'component/common/lbc-symbol';
|
import CurrencySymbol from 'component/common/lbc-symbol';
|
||||||
import CreditAmount from 'component/common/credit-amount';
|
import CreditAmount from 'component/common/credit-amount';
|
||||||
import Button from 'component/button';
|
import Button from 'component/button';
|
||||||
|
|
||||||
const ModalCreditIntro = props => {
|
type Props = {
|
||||||
|
totalRewardValue: number,
|
||||||
|
currentBalance: number,
|
||||||
|
closeModal: () => void,
|
||||||
|
addBalance: () => void,
|
||||||
|
};
|
||||||
|
|
||||||
|
const ModalCreditIntro = (props: Props) => {
|
||||||
const { closeModal, totalRewardValue, currentBalance, addBalance } = props;
|
const { closeModal, totalRewardValue, currentBalance, addBalance } = props;
|
||||||
const totalRewardRounded = Math.round(totalRewardValue / 10) * 10;
|
const totalRewardRounded = Math.round(totalRewardValue / 10) * 10;
|
||||||
|
|
||||||
|
@ -25,16 +31,13 @@ const ModalCreditIntro = props => {
|
||||||
can take are limited.
|
can take are limited.
|
||||||
</p>
|
</p>
|
||||||
)}
|
)}
|
||||||
<p>
|
{Boolean(totalRewardValue) && (
|
||||||
There are a variety of ways to get credits, including more than{' '}
|
<p>
|
||||||
{totalRewardValue ? (
|
There are a variety of ways to get credits, including more than{' '}
|
||||||
<CreditAmount noStyle amount={totalRewardRounded} />
|
<CreditAmount noStyle amount={totalRewardRounded} />{' '}
|
||||||
) : (
|
{__('in free rewards for participating in the LBRY beta.')}
|
||||||
<span className="credit-amount">{__('?? credits')}</span>
|
</p>
|
||||||
)}{' '}
|
)}
|
||||||
{__(' in free rewards for participating in the LBRY beta.')}
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<div className="card__actions card__actions--center">
|
<div className="card__actions card__actions--center">
|
||||||
<Button button="primary" onClick={addBalance} label={__('Get Credits')} />
|
<Button button="primary" onClick={addBalance} label={__('Get Credits')} />
|
||||||
<Button
|
<Button
|
||||||
|
@ -49,4 +52,3 @@ const ModalCreditIntro = props => {
|
||||||
};
|
};
|
||||||
|
|
||||||
export default ModalCreditIntro;
|
export default ModalCreditIntro;
|
||||||
/* esline-enable */
|
|
||||||
|
|
|
@ -8,7 +8,7 @@ const select = state => {
|
||||||
const selectReward = makeSelectRewardByType();
|
const selectReward = makeSelectRewardByType();
|
||||||
|
|
||||||
return {
|
return {
|
||||||
reward: selectReward(state, { reward_type: rewards.TYPE_NEW_USER }),
|
reward: selectReward(state, rewards.TYPE_NEW_USER),
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,7 @@ import CreditAmount from 'component/common/credit-amount';
|
||||||
|
|
||||||
class ModalFirstReward extends React.PureComponent {
|
class ModalFirstReward extends React.PureComponent {
|
||||||
render() {
|
render() {
|
||||||
const { closeModal, reward } = this.props;
|
const { closeModal } = this.props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal
|
<Modal
|
||||||
|
@ -18,10 +18,7 @@ class ModalFirstReward extends React.PureComponent {
|
||||||
>
|
>
|
||||||
<section>
|
<section>
|
||||||
<h3 className="modal__header">{__('Your First Reward')}</h3>
|
<h3 className="modal__header">{__('Your First Reward')}</h3>
|
||||||
<p>
|
<p>{__('You just earned your first reward!')}</p>
|
||||||
{__('You just earned your first reward of')}{' '}
|
|
||||||
<CreditAmount amount={reward.reward_amount} />.
|
|
||||||
</p>
|
|
||||||
<p>
|
<p>
|
||||||
{__(
|
{__(
|
||||||
"This reward will show in your Wallet in the top right momentarily (if it hasn't already)."
|
"This reward will show in your Wallet in the top right momentarily (if it hasn't already)."
|
||||||
|
|
|
@ -1,8 +1,14 @@
|
||||||
|
// @flow
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Modal } from 'modal/modal';
|
import { Modal } from 'modal/modal';
|
||||||
import Button from 'component/button';
|
import Button from 'component/button';
|
||||||
|
|
||||||
class ModalIncompatibleDaemon extends React.PureComponent {
|
type Props = {
|
||||||
|
quit: () => void,
|
||||||
|
quitAnyDaemon: () => void,
|
||||||
|
};
|
||||||
|
|
||||||
|
class ModalIncompatibleDaemon extends React.PureComponent<Props> {
|
||||||
render() {
|
render() {
|
||||||
const { quit, quitAnyDaemon } = this.props;
|
const { quit, quitAnyDaemon } = this.props;
|
||||||
|
|
||||||
|
@ -19,7 +25,11 @@ class ModalIncompatibleDaemon extends React.PureComponent {
|
||||||
{__(
|
{__(
|
||||||
'This browser is running with an incompatible version of the LBRY protocol and your install must be repaired. '
|
'This browser is running with an incompatible version of the LBRY protocol and your install must be repaired. '
|
||||||
)}
|
)}
|
||||||
<Button label={__('Learn more')} href="https://lbry.io/faq/incompatible-protocol-version" />
|
<Button
|
||||||
|
button="link"
|
||||||
|
label={__('Learn more')}
|
||||||
|
href="https://lbry.io/faq/incompatible-protocol-version"
|
||||||
|
/>
|
||||||
</Modal>
|
</Modal>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,9 +18,9 @@ import ModalRevokeClaim from 'modal/modalRevokeClaim';
|
||||||
import ModalEmailCollection from 'modal/modalEmailCollection';
|
import ModalEmailCollection from 'modal/modalEmailCollection';
|
||||||
import ModalPhoneCollection from 'modal/modalPhoneCollection';
|
import ModalPhoneCollection from 'modal/modalPhoneCollection';
|
||||||
import ModalFirstSubscription from 'modal/modalFirstSubscription';
|
import ModalFirstSubscription from 'modal/modalFirstSubscription';
|
||||||
|
import ModalConfirmTransaction from 'modal/modalConfirmTransaction';
|
||||||
import ModalSendTip from '../modalSendTip';
|
import ModalSendTip from '../modalSendTip';
|
||||||
import ModalPublish from '../modalPublish';
|
import ModalPublish from '../modalPublish';
|
||||||
import ModalSearch from '../modalSearch';
|
|
||||||
import ModalOpenExternalLink from '../modalOpenExternalLink';
|
import ModalOpenExternalLink from '../modalOpenExternalLink';
|
||||||
|
|
||||||
class ModalRouter extends React.PureComponent {
|
class ModalRouter extends React.PureComponent {
|
||||||
|
@ -154,10 +154,10 @@ class ModalRouter extends React.PureComponent {
|
||||||
return <ModalSendTip {...notificationProps} />;
|
return <ModalSendTip {...notificationProps} />;
|
||||||
case MODALS.PUBLISH:
|
case MODALS.PUBLISH:
|
||||||
return <ModalPublish {...notificationProps} />;
|
return <ModalPublish {...notificationProps} />;
|
||||||
case MODALS.SEARCH:
|
|
||||||
return <ModalSearch {...notificationProps} />;
|
|
||||||
case MODALS.CONFIRM_EXTERNAL_LINK:
|
case MODALS.CONFIRM_EXTERNAL_LINK:
|
||||||
return <ModalOpenExternalLink {...notificationProps} />;
|
return <ModalOpenExternalLink {...notificationProps} />;
|
||||||
|
case MODALS.CONFIRM_TRANSACTION:
|
||||||
|
return <ModalConfirmTransaction {...notificationProps} />;
|
||||||
default:
|
default:
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +0,0 @@
|
||||||
import { connect } from 'react-redux';
|
|
||||||
import { doHideNotification } from 'lbry-redux';
|
|
||||||
import ModalSearch from './view';
|
|
||||||
import { doClearPublish } from 'redux/actions/publish';
|
|
||||||
import { doNavigate } from 'redux/actions/navigation';
|
|
||||||
|
|
||||||
const perform = dispatch => ({
|
|
||||||
closeModal: () => dispatch(doHideNotification()),
|
|
||||||
clearPublish: () => dispatch(doClearPublish()),
|
|
||||||
navigate: (path, params) => dispatch(doNavigate(path, params)),
|
|
||||||
});
|
|
||||||
|
|
||||||
export default connect(null, perform)(ModalSearch);
|
|
|
@ -1,25 +0,0 @@
|
||||||
// @flow
|
|
||||||
import React from 'react';
|
|
||||||
import { Modal } from 'modal/modal';
|
|
||||||
import SearchPage from 'page/search';
|
|
||||||
import Button from 'component/button';
|
|
||||||
import * as icons from 'constants/icons';
|
|
||||||
|
|
||||||
type Props = {
|
|
||||||
closeModal: () => void,
|
|
||||||
query: string,
|
|
||||||
};
|
|
||||||
|
|
||||||
class ModalSearch extends React.PureComponent<Props> {
|
|
||||||
render() {
|
|
||||||
const { closeModal, query } = this.props;
|
|
||||||
return (
|
|
||||||
<Modal isOpen type="custom" fullScreen>
|
|
||||||
<Button noPadding button="alt" icon={icons.CLOSE} onClick={closeModal} />
|
|
||||||
<SearchPage />
|
|
||||||
</Modal>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default ModalSearch;
|
|
|
@ -6,7 +6,6 @@ import {
|
||||||
makeSelectFetchingChannelClaims,
|
makeSelectFetchingChannelClaims,
|
||||||
makeSelectCurrentParam,
|
makeSelectCurrentParam,
|
||||||
selectCurrentParams,
|
selectCurrentParams,
|
||||||
doNotify,
|
|
||||||
} from 'lbry-redux';
|
} from 'lbry-redux';
|
||||||
import { doNavigate } from 'redux/actions/navigation';
|
import { doNavigate } from 'redux/actions/navigation';
|
||||||
import { makeSelectTotalPagesForChannel } from 'redux/selectors/content';
|
import { makeSelectTotalPagesForChannel } from 'redux/selectors/content';
|
||||||
|
@ -25,7 +24,6 @@ const perform = dispatch => ({
|
||||||
fetchClaims: (uri, page) => dispatch(doFetchClaimsByChannel(uri, page)),
|
fetchClaims: (uri, page) => dispatch(doFetchClaimsByChannel(uri, page)),
|
||||||
fetchClaimCount: uri => dispatch(doFetchClaimCountByChannel(uri)),
|
fetchClaimCount: uri => dispatch(doFetchClaimCountByChannel(uri)),
|
||||||
navigate: (path, params) => dispatch(doNavigate(path, params)),
|
navigate: (path, params) => dispatch(doNavigate(path, params)),
|
||||||
openModal: (modal, props) => dispatch(doNotify(modal, props)),
|
|
||||||
});
|
});
|
||||||
|
|
||||||
export default connect(select, perform)(ChannelPage);
|
export default connect(select, perform)(ChannelPage);
|
||||||
|
|
|
@ -4,6 +4,7 @@ import BusyIndicator from 'component/common/busy-indicator';
|
||||||
import { FormField, FormRow } from 'component/common/form';
|
import { FormField, FormRow } from 'component/common/form';
|
||||||
import ReactPaginate from 'react-paginate';
|
import ReactPaginate from 'react-paginate';
|
||||||
import SubscribeButton from 'component/subscribeButton';
|
import SubscribeButton from 'component/subscribeButton';
|
||||||
|
import ViewOnWebButton from 'component/viewOnWebButton';
|
||||||
import Page from 'component/page';
|
import Page from 'component/page';
|
||||||
import FileList from 'component/fileList';
|
import FileList from 'component/fileList';
|
||||||
import type { Claim } from 'types/claim';
|
import type { Claim } from 'types/claim';
|
||||||
|
@ -47,17 +48,24 @@ class ChannelPage extends React.PureComponent<Props> {
|
||||||
this.props.navigate('/show', newParams);
|
this.props.navigate('/show', newParams);
|
||||||
}
|
}
|
||||||
|
|
||||||
paginate(e, totalPages) {
|
paginate(e, totalPages: number) {
|
||||||
// Change page if enter was pressed, and the given page is between
|
// Change page if enter was pressed, and the given page is between
|
||||||
// the first and the last.
|
// the first and the last.
|
||||||
if (e.keyCode === 13 && e.target.value > 0 && e.target.value <= totalPages) {
|
const pageFromInput = Number(e.target.value);
|
||||||
this.changePage(e.target.value);
|
|
||||||
|
if (
|
||||||
|
e.keyCode === 13 &&
|
||||||
|
!Number.isNaN(pageFromInput) &&
|
||||||
|
pageFromInput > 0 &&
|
||||||
|
pageFromInput <= totalPages
|
||||||
|
) {
|
||||||
|
this.changePage(pageFromInput);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { fetching, claimsInChannel, claim, page, totalPages } = this.props;
|
const { fetching, claimsInChannel, claim, page, totalPages } = this.props;
|
||||||
const { name, permanent_url: permanentUrl } = claim;
|
const { name, permanent_url: permanentUrl, claim_id: claimId } = claim;
|
||||||
|
|
||||||
let contentList;
|
let contentList;
|
||||||
if (fetching) {
|
if (fetching) {
|
||||||
|
@ -77,6 +85,7 @@ class ChannelPage extends React.PureComponent<Props> {
|
||||||
<h1>{name}</h1>
|
<h1>{name}</h1>
|
||||||
<div className="card__actions card__actions--no-margin">
|
<div className="card__actions card__actions--no-margin">
|
||||||
<SubscribeButton uri={permanentUrl} channelName={name} />
|
<SubscribeButton uri={permanentUrl} channelName={name} />
|
||||||
|
<ViewOnWebButton uri={`${name}:${claimId}`} />
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
<section>{contentList}</section>
|
<section>{contentList}</section>
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
// @flow
|
// @flow
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import Page from 'component/page';
|
import Page from 'component/page';
|
||||||
import CategoryList from 'component/common/category-list';
|
import CategoryList from 'component/categoryList';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
fetchFeaturedUris: () => void,
|
fetchFeaturedUris: () => void,
|
||||||
|
@ -27,7 +27,11 @@ class DiscoverPage extends React.PureComponent<Props> {
|
||||||
featuredUris[category].length ? (
|
featuredUris[category].length ? (
|
||||||
<CategoryList key={category} category={category} names={featuredUris[category]} />
|
<CategoryList key={category} category={category} names={featuredUris[category]} />
|
||||||
) : (
|
) : (
|
||||||
''
|
<CategoryList
|
||||||
|
key={category}
|
||||||
|
category={category.split('#')[0]}
|
||||||
|
categoryLink={category}
|
||||||
|
/>
|
||||||
)
|
)
|
||||||
)}
|
)}
|
||||||
{failedToLoad && <div className="empty">{__('Failed to load landing content.')}</div>}
|
{failedToLoad && <div className="empty">{__('Failed to load landing content.')}</div>}
|
||||||
|
|
|
@ -33,7 +33,7 @@ const select = (state, props) => ({
|
||||||
playingUri: selectPlayingUri(state),
|
playingUri: selectPlayingUri(state),
|
||||||
isPaused: selectMediaPaused(state),
|
isPaused: selectMediaPaused(state),
|
||||||
claimIsMine: makeSelectClaimIsMine(props.uri)(state),
|
claimIsMine: makeSelectClaimIsMine(props.uri)(state),
|
||||||
autoplay: makeSelectClientSetting(settings.AUTOPLAY)(state)
|
autoplay: makeSelectClientSetting(settings.AUTOPLAY)(state),
|
||||||
});
|
});
|
||||||
|
|
||||||
const perform = dispatch => ({
|
const perform = dispatch => ({
|
||||||
|
|
|
@ -13,10 +13,13 @@ import DateTime from 'component/dateTime';
|
||||||
import * as icons from 'constants/icons';
|
import * as icons from 'constants/icons';
|
||||||
import Button from 'component/button';
|
import Button from 'component/button';
|
||||||
import SubscribeButton from 'component/subscribeButton';
|
import SubscribeButton from 'component/subscribeButton';
|
||||||
|
import ViewOnWebButton from 'component/viewOnWebButton';
|
||||||
import Page from 'component/page';
|
import Page from 'component/page';
|
||||||
import player from 'render-media';
|
import player from 'render-media';
|
||||||
import * as settings from 'constants/settings';
|
import * as settings from 'constants/settings';
|
||||||
import type { Claim } from 'types/claim';
|
import type { Claim } from 'types/claim';
|
||||||
|
import type { Subscription } from 'types/subscription';
|
||||||
|
import FileDownloadLink from 'component/fileDownloadLink';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
claim: Claim,
|
claim: Claim,
|
||||||
|
@ -30,8 +33,6 @@ type Props = {
|
||||||
uri: string,
|
uri: string,
|
||||||
rewardedContentClaimIds: Array<string>,
|
rewardedContentClaimIds: Array<string>,
|
||||||
obscureNsfw: boolean,
|
obscureNsfw: boolean,
|
||||||
playingUri: ?string,
|
|
||||||
isPaused: boolean,
|
|
||||||
claimIsMine: boolean,
|
claimIsMine: boolean,
|
||||||
autoplay: boolean,
|
autoplay: boolean,
|
||||||
costInfo: ?{},
|
costInfo: ?{},
|
||||||
|
@ -39,10 +40,10 @@ type Props = {
|
||||||
openModal: ({ id: string }, { uri: string }) => void,
|
openModal: ({ id: string }, { uri: string }) => void,
|
||||||
fetchFileInfo: string => void,
|
fetchFileInfo: string => void,
|
||||||
fetchCostInfo: string => void,
|
fetchCostInfo: string => void,
|
||||||
prepareEdit: ({}) => void,
|
prepareEdit: ({}, string) => void,
|
||||||
setClientSetting: (string, boolean | string) => void,
|
setClientSetting: (string, boolean | string) => void,
|
||||||
checkSubscription: ({ channelName: string, uri: string }) => void,
|
checkSubscription: ({ channelName: string, uri: string }) => void,
|
||||||
subscriptions: Array<{}>,
|
subscriptions: Array<Subscription>,
|
||||||
};
|
};
|
||||||
|
|
||||||
class FilePage extends React.Component<Props> {
|
class FilePage extends React.Component<Props> {
|
||||||
|
@ -78,12 +79,7 @@ class FilePage extends React.Component<Props> {
|
||||||
}
|
}
|
||||||
|
|
||||||
checkSubscription = (props: Props) => {
|
checkSubscription = (props: Props) => {
|
||||||
if (
|
if (props.subscriptions.find(sub => sub.channelName === props.claim.channel_name)) {
|
||||||
props.claim.value.publisherSignature &&
|
|
||||||
props.subscriptions
|
|
||||||
.map(subscription => subscription.channelName)
|
|
||||||
.indexOf(props.claim.channel_name) !== -1
|
|
||||||
) {
|
|
||||||
props.checkSubscription({
|
props.checkSubscription({
|
||||||
channelName: props.claim.channel_name,
|
channelName: props.claim.channel_name,
|
||||||
uri: buildURI(
|
uri: buildURI(
|
||||||
|
@ -105,13 +101,12 @@ class FilePage extends React.Component<Props> {
|
||||||
uri,
|
uri,
|
||||||
rewardedContentClaimIds,
|
rewardedContentClaimIds,
|
||||||
obscureNsfw,
|
obscureNsfw,
|
||||||
playingUri,
|
|
||||||
isPaused,
|
|
||||||
openModal,
|
openModal,
|
||||||
claimIsMine,
|
claimIsMine,
|
||||||
prepareEdit,
|
prepareEdit,
|
||||||
navigate,
|
navigate,
|
||||||
autoplay,
|
autoplay,
|
||||||
|
costInfo,
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
// File info
|
// File info
|
||||||
|
@ -128,8 +123,20 @@ class FilePage extends React.Component<Props> {
|
||||||
if (channelName && channelClaimId) {
|
if (channelName && channelClaimId) {
|
||||||
subscriptionUri = buildURI({ channelName, claimId: channelClaimId }, false);
|
subscriptionUri = buildURI({ channelName, claimId: channelClaimId }, false);
|
||||||
}
|
}
|
||||||
|
const speechSharable =
|
||||||
|
costInfo &&
|
||||||
|
costInfo.cost === 0 &&
|
||||||
|
contentType &&
|
||||||
|
['video', 'image'].includes(contentType.split('/')[0]);
|
||||||
|
|
||||||
|
// We want to use the short form uri for editing
|
||||||
|
// This is what the user is used to seeing, they don't care about the claim id
|
||||||
|
// We will select the claim id before they publish
|
||||||
|
let editUri;
|
||||||
|
if (claimIsMine) {
|
||||||
|
editUri = buildURI({ channelName, contentName: claim.name });
|
||||||
|
}
|
||||||
|
|
||||||
const isPlaying = playingUri === uri && !isPaused;
|
|
||||||
return (
|
return (
|
||||||
<Page extraPadding>
|
<Page extraPadding>
|
||||||
{!claim || !metadata ? (
|
{!claim || !metadata ? (
|
||||||
|
@ -143,17 +150,14 @@ class FilePage extends React.Component<Props> {
|
||||||
) : (
|
) : (
|
||||||
<Thumbnail shouldObscure={shouldObscureThumbnail} src={thumbnail} />
|
<Thumbnail shouldObscure={shouldObscureThumbnail} src={thumbnail} />
|
||||||
)}
|
)}
|
||||||
{!isPlaying && (
|
|
||||||
<div className="card-media__internal-links">
|
|
||||||
<FileActions uri={uri} vertical />
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
<div className="card__content">
|
<div className="card__content">
|
||||||
<div className="card__title-identity--file">
|
<div className="card__title-identity--file">
|
||||||
<h1 className="card__title card__title--file">{title}</h1>
|
<h1 className="card__title card__title--file">{title}</h1>
|
||||||
<div className="card__title-identity-icons">
|
<div className="card__title-identity-icons">
|
||||||
<FilePrice uri={normalizeURI(uri)} />
|
<FilePrice uri={normalizeURI(uri)} />
|
||||||
{isRewardContent && <Icon icon={icons.FEATURED} />}
|
{isRewardContent && (
|
||||||
|
<Icon iconColor="red" tooltip="bottom" icon={icons.FEATURED} />
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<span className="card__subtitle card__subtitle--file">
|
<span className="card__subtitle card__subtitle--file">
|
||||||
|
@ -163,6 +167,7 @@ class FilePage extends React.Component<Props> {
|
||||||
{metadata.nsfw && <div>NSFW</div>}
|
{metadata.nsfw && <div>NSFW</div>}
|
||||||
<div className="card__channel-info">
|
<div className="card__channel-info">
|
||||||
<UriIndicator uri={uri} link />
|
<UriIndicator uri={uri} link />
|
||||||
|
|
||||||
<div className="card__actions card__actions--no-margin">
|
<div className="card__actions card__actions--no-margin">
|
||||||
{claimIsMine ? (
|
{claimIsMine ? (
|
||||||
<Button
|
<Button
|
||||||
|
@ -170,7 +175,7 @@ class FilePage extends React.Component<Props> {
|
||||||
icon={icons.EDIT}
|
icon={icons.EDIT}
|
||||||
label={__('Edit')}
|
label={__('Edit')}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
prepareEdit(claim, uri);
|
prepareEdit(claim, editUri);
|
||||||
navigate('/publish');
|
navigate('/publish');
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
@ -185,6 +190,14 @@ class FilePage extends React.Component<Props> {
|
||||||
<SubscribeButton uri={subscriptionUri} channelName={channelName} />
|
<SubscribeButton uri={subscriptionUri} channelName={channelName} />
|
||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
)}
|
)}
|
||||||
|
{speechSharable && (
|
||||||
|
<ViewOnWebButton
|
||||||
|
uri={buildURI({
|
||||||
|
claimId: claim.claim_id,
|
||||||
|
contentName: claim.name,
|
||||||
|
}).slice(7)}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<FormRow alignRight>
|
<FormRow alignRight>
|
||||||
|
@ -199,6 +212,11 @@ class FilePage extends React.Component<Props> {
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="card__content">
|
<div className="card__content">
|
||||||
|
<FileDownloadLink uri={uri} />
|
||||||
|
<FileActions uri={uri} claimId={claim.claim_id} />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="card__content--extra-padding">
|
||||||
<FileDetails uri={uri} />
|
<FileDetails uri={uri} />
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
|
@ -1,26 +1,20 @@
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { doClaimRewardType } from 'redux/actions/rewards';
|
|
||||||
import {
|
import {
|
||||||
doHistoryBack,
|
|
||||||
doResolveUri,
|
doResolveUri,
|
||||||
makeSelectCostInfoForUri,
|
makeSelectCostInfoForUri,
|
||||||
selectMyClaims,
|
selectMyClaims,
|
||||||
selectFetchingMyChannels,
|
|
||||||
selectMyChannelClaims,
|
|
||||||
selectClaimsByUri,
|
selectClaimsByUri,
|
||||||
selectResolvingUris,
|
selectResolvingUris,
|
||||||
selectBalance,
|
selectBalance,
|
||||||
} from 'lbry-redux';
|
} from 'lbry-redux';
|
||||||
import {
|
|
||||||
doFetchClaimListMine,
|
|
||||||
doFetchChannelListMine,
|
|
||||||
doCreateChannel,
|
|
||||||
} from 'redux/actions/content';
|
|
||||||
import { doNavigate } from 'redux/actions/navigation';
|
import { doNavigate } from 'redux/actions/navigation';
|
||||||
import rewards from 'rewards';
|
|
||||||
import { selectPublishFormValues } from 'redux/selectors/publish';
|
import { selectPublishFormValues } from 'redux/selectors/publish';
|
||||||
import { doClearPublish, doUpdatePublishForm, doPublish } from 'redux/actions/publish';
|
import {
|
||||||
import { doPrepareEdit } from 'redux/actions/publish';
|
doClearPublish,
|
||||||
|
doUpdatePublishForm,
|
||||||
|
doPublish,
|
||||||
|
doPrepareEdit,
|
||||||
|
} from 'redux/actions/publish';
|
||||||
import PublishPage from './view';
|
import PublishPage from './view';
|
||||||
|
|
||||||
const select = (state, props) => {
|
const select = (state, props) => {
|
||||||
|
|
|
@ -14,6 +14,9 @@ type Props = {
|
||||||
rewards: Array<{ reward_type: boolean }>,
|
rewards: Array<{ reward_type: boolean }>,
|
||||||
user: ?{
|
user: ?{
|
||||||
is_identity_verified: boolean,
|
is_identity_verified: boolean,
|
||||||
|
is_reward_approved: boolean,
|
||||||
|
primary_email: string,
|
||||||
|
has_verified_email: boolean,
|
||||||
},
|
},
|
||||||
daemonSettings: {
|
daemonSettings: {
|
||||||
share_usage_data: boolean,
|
share_usage_data: boolean,
|
||||||
|
@ -46,7 +49,7 @@ class RewardsPage extends React.PureComponent<Props> {
|
||||||
renderPageHeader() {
|
renderPageHeader() {
|
||||||
const { doAuth, navigate, user, daemonSettings } = this.props;
|
const { doAuth, navigate, user, daemonSettings } = this.props;
|
||||||
|
|
||||||
if (user && !user.is_reward_approved && daemonSettings.share_usage_data) {
|
if (user && !user.is_reward_approved && daemonSettings && daemonSettings.share_usage_data) {
|
||||||
if (!user.primary_email || !user.has_verified_email || !user.is_identity_verified) {
|
if (!user.primary_email || !user.has_verified_email || !user.is_identity_verified) {
|
||||||
return (
|
return (
|
||||||
<section className="card card--section">
|
<section className="card card--section">
|
||||||
|
@ -95,7 +98,7 @@ class RewardsPage extends React.PureComponent<Props> {
|
||||||
renderUnclaimedRewards() {
|
renderUnclaimedRewards() {
|
||||||
const { fetching, rewards, user, daemonSettings, navigate } = this.props;
|
const { fetching, rewards, user, daemonSettings, navigate } = this.props;
|
||||||
|
|
||||||
if (!daemonSettings.share_usage_data) {
|
if (daemonSettings && !daemonSettings.share_usage_data) {
|
||||||
return (
|
return (
|
||||||
<div className="card card--section">
|
<div className="card card--section">
|
||||||
<div className="card__title">{__('Disabled')}</div>
|
<div className="card__title">{__('Disabled')}</div>
|
||||||
|
@ -131,8 +134,7 @@ class RewardsPage extends React.PureComponent<Props> {
|
||||||
}
|
}
|
||||||
|
|
||||||
const isNotEligible =
|
const isNotEligible =
|
||||||
!user || !user.primary_email || !user.has_verified_email || !user.is_identity_verified;
|
!user || !user.primary_email || !user.has_verified_email || !user.is_reward_approved;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={classnames('card__list--rewards', {
|
className={classnames('card__list--rewards', {
|
||||||
|
|
|
@ -5,12 +5,13 @@ import FileTile from 'component/fileTile';
|
||||||
import FileListSearch from 'component/fileListSearch';
|
import FileListSearch from 'component/fileListSearch';
|
||||||
import ToolTip from 'component/common/tooltip';
|
import ToolTip from 'component/common/tooltip';
|
||||||
import Page from 'component/page';
|
import Page from 'component/page';
|
||||||
|
import Icon from 'component/common/icon';
|
||||||
|
import * as icons from 'constants/icons';
|
||||||
|
|
||||||
const MODAL_ANIMATION_TIME = 250;
|
const MODAL_ANIMATION_TIME = 250;
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
query: ?string,
|
query: ?string,
|
||||||
updateSearchQuery: string => void,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class SearchPage extends React.PureComponent<Props> {
|
class SearchPage extends React.PureComponent<Props> {
|
||||||
|
@ -33,33 +34,25 @@ class SearchPage extends React.PureComponent<Props> {
|
||||||
input: ?HTMLInputElement;
|
input: ?HTMLInputElement;
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { query, updateSearchQuery } = this.props;
|
const { query } = this.props;
|
||||||
return (
|
return (
|
||||||
<Page noPadding>
|
<Page>
|
||||||
<div className="search__wrapper">
|
{isURIValid(query) && (
|
||||||
<input
|
<React.Fragment>
|
||||||
ref={input => (this.input = input)}
|
<div className="file-list__header">
|
||||||
className="search__input"
|
{__('Exact URL')}
|
||||||
value={query}
|
<ToolTip
|
||||||
placeholder={__('Search for anything...')}
|
icon
|
||||||
onChange={event => updateSearchQuery(event.target.value)}
|
body={__('This is the resolution of a LBRY URL and not controlled by LBRY Inc.')}
|
||||||
/>
|
>
|
||||||
|
<Icon icon={icons.HELP} />
|
||||||
{isURIValid(query) && (
|
</ToolTip>
|
||||||
<React.Fragment>
|
</div>
|
||||||
<div className="file-list__header">
|
<FileTile fullWidth uri={normalizeURI(query)} showUri />
|
||||||
{__('Exact URL')}
|
</React.Fragment>
|
||||||
<ToolTip
|
)}
|
||||||
label="?"
|
<FileListSearch query={query} />
|
||||||
body={__('This is the resolution of a LBRY URL and not controlled by LBRY Inc.')}
|
<div className="help">{__('These search results are provided by LBRY, Inc.')}</div>
|
||||||
className="tooltip--header"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<FileTile fullWidth uri={normalizeURI(query)} showUri />
|
|
||||||
</React.Fragment>
|
|
||||||
)}
|
|
||||||
<FileListSearch query={query} />
|
|
||||||
</div>
|
|
||||||
</Page>
|
</Page>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,7 +26,7 @@ const select = state => ({
|
||||||
language: selectCurrentLanguage(state),
|
language: selectCurrentLanguage(state),
|
||||||
languages: selectLanguages(state),
|
languages: selectLanguages(state),
|
||||||
automaticDarkModeEnabled: makeSelectClientSetting(settings.AUTOMATIC_DARK_MODE_ENABLED)(state),
|
automaticDarkModeEnabled: makeSelectClientSetting(settings.AUTOMATIC_DARK_MODE_ENABLED)(state),
|
||||||
autoplay: makeSelectClientSetting(settings.AUTOPLAY)(state)
|
autoplay: makeSelectClientSetting(settings.AUTOPLAY)(state),
|
||||||
});
|
});
|
||||||
|
|
||||||
const perform = dispatch => ({
|
const perform = dispatch => ({
|
||||||
|
|
|
@ -31,7 +31,7 @@ type Props = {
|
||||||
currentTheme: string,
|
currentTheme: string,
|
||||||
themes: Array<string>,
|
themes: Array<string>,
|
||||||
automaticDarkModeEnabled: boolean,
|
automaticDarkModeEnabled: boolean,
|
||||||
autoplay: boolean
|
autoplay: boolean,
|
||||||
};
|
};
|
||||||
|
|
||||||
type State = {
|
type State = {
|
||||||
|
@ -144,7 +144,7 @@ class SettingsPage extends React.PureComponent<Props, State> {
|
||||||
currentTheme,
|
currentTheme,
|
||||||
themes,
|
themes,
|
||||||
automaticDarkModeEnabled,
|
automaticDarkModeEnabled,
|
||||||
autoplay
|
autoplay,
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
const noDaemonSettings = !daemonSettings || Object.keys(daemonSettings).length === 0;
|
const noDaemonSettings = !daemonSettings || Object.keys(daemonSettings).length === 0;
|
||||||
|
|
|
@ -251,12 +251,21 @@ export function doCheckUpgradeSubscribe() {
|
||||||
export function doCheckDaemonVersion() {
|
export function doCheckDaemonVersion() {
|
||||||
return dispatch => {
|
return dispatch => {
|
||||||
Lbry.version().then(({ lbrynet_version: lbrynetVersion }) => {
|
Lbry.version().then(({ lbrynet_version: lbrynetVersion }) => {
|
||||||
|
if (config.lbrynetDaemonVersion === lbrynetVersion) {
|
||||||
|
dispatch({
|
||||||
|
type: ACTIONS.DAEMON_VERSION_MATCH,
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
dispatch({
|
dispatch({
|
||||||
type:
|
type: ACTIONS.DAEMON_VERSION_MISMATCH,
|
||||||
config.lbrynetDaemonVersion === lbrynetVersion
|
|
||||||
? ACTIONS.DAEMON_VERSION_MATCH
|
|
||||||
: ACTIONS.DAEMON_VERSION_MISMATCH,
|
|
||||||
});
|
});
|
||||||
|
dispatch(
|
||||||
|
doNotify({
|
||||||
|
id: MODALS.INCOMPATIBLE_DAEMON,
|
||||||
|
})
|
||||||
|
);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,10 +42,10 @@ export function doFetchFeaturedUris() {
|
||||||
});
|
});
|
||||||
|
|
||||||
const success = ({ Uris }) => {
|
const success = ({ Uris }) => {
|
||||||
let urisToResolve = [];
|
const urisToResolve = Object.keys(Uris).reduce(
|
||||||
Object.keys(Uris).forEach(category => {
|
(resolve, category) => [...resolve, ...Uris[category]],
|
||||||
urisToResolve = [...urisToResolve, ...Uris[category]];
|
[]
|
||||||
});
|
);
|
||||||
|
|
||||||
const actions = [
|
const actions = [
|
||||||
doResolveUris(urisToResolve),
|
doResolveUris(urisToResolve),
|
||||||
|
@ -225,7 +225,11 @@ export function doDownloadFile(uri, streamInfo) {
|
||||||
return dispatch => {
|
return dispatch => {
|
||||||
dispatch(doStartDownload(uri, streamInfo.outpoint));
|
dispatch(doStartDownload(uri, streamInfo.outpoint));
|
||||||
|
|
||||||
analytics.apiLogView(uri, streamInfo.output, streamInfo.claim_id);
|
analytics.apiLogView(
|
||||||
|
`${streamInfo.claim_name}#${streamInfo.claim_id}`,
|
||||||
|
streamInfo.outpoint,
|
||||||
|
streamInfo.claim_id
|
||||||
|
);
|
||||||
|
|
||||||
dispatch(doClaimEligiblePurchaseRewards());
|
dispatch(doClaimEligiblePurchaseRewards());
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,12 +1,18 @@
|
||||||
// @flow
|
// @flow
|
||||||
import { ACTIONS, Lbry, selectMyClaimsWithoutChannels, doNotify, MODALS } from 'lbry-redux';
|
import {
|
||||||
|
ACTIONS,
|
||||||
|
Lbry,
|
||||||
|
selectMyClaimsWithoutChannels,
|
||||||
|
doNotify,
|
||||||
|
MODALS,
|
||||||
|
selectMyChannelClaims,
|
||||||
|
} from 'lbry-redux';
|
||||||
import { selectPendingPublishes } from 'redux/selectors/publish';
|
import { selectPendingPublishes } from 'redux/selectors/publish';
|
||||||
import type {
|
import type {
|
||||||
UpdatePublishFormData,
|
UpdatePublishFormData,
|
||||||
UpdatePublishFormAction,
|
UpdatePublishFormAction,
|
||||||
PublishParams,
|
PublishParams,
|
||||||
} from 'redux/reducers/publish';
|
} from 'redux/reducers/publish';
|
||||||
import { CHANNEL_NEW, CHANNEL_ANONYMOUS } from 'constants/claim';
|
|
||||||
|
|
||||||
type Action = UpdatePublishFormAction | { type: ACTIONS.CLEAR_PUBLISH };
|
type Action = UpdatePublishFormAction | { type: ACTIONS.CLEAR_PUBLISH };
|
||||||
type PromiseAction = Promise<Action>;
|
type PromiseAction = Promise<Action>;
|
||||||
|
@ -74,6 +80,7 @@ export const doPrepareEdit = (claim: any, uri: string) => (dispatch: Dispatch) =
|
||||||
export const doPublish = (params: PublishParams) => (dispatch: Dispatch, getState: () => {}) => {
|
export const doPublish = (params: PublishParams) => (dispatch: Dispatch, getState: () => {}) => {
|
||||||
const state = getState();
|
const state = getState();
|
||||||
const myClaims = selectMyClaimsWithoutChannels(state);
|
const myClaims = selectMyClaimsWithoutChannels(state);
|
||||||
|
const myChannels = selectMyChannelClaims(state);
|
||||||
|
|
||||||
const {
|
const {
|
||||||
name,
|
name,
|
||||||
|
@ -93,6 +100,10 @@ export const doPublish = (params: PublishParams) => (dispatch: Dispatch, getStat
|
||||||
sources,
|
sources,
|
||||||
} = params;
|
} = params;
|
||||||
|
|
||||||
|
// get the claim id from the channel name, we will use that instead
|
||||||
|
const namedChannelClaim = myChannels.find(myChannel => myChannel.name === channel);
|
||||||
|
const channelId = namedChannelClaim ? namedChannelClaim.claim_id : '';
|
||||||
|
|
||||||
let isEdit;
|
let isEdit;
|
||||||
const newPublishName = channel ? `${channel}/${name}` : name;
|
const newPublishName = channel ? `${channel}/${name}` : name;
|
||||||
for (let i = 0; i < myClaims.length; i += 1) {
|
for (let i = 0; i < myClaims.length; i += 1) {
|
||||||
|
@ -104,7 +115,6 @@ export const doPublish = (params: PublishParams) => (dispatch: Dispatch, getStat
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const channelName = channel === CHANNEL_ANONYMOUS || channel === CHANNEL_NEW ? '' : channel;
|
|
||||||
const fee = contentIsFree || !price.amount ? undefined : { ...price };
|
const fee = contentIsFree || !price.amount ? undefined : { ...price };
|
||||||
|
|
||||||
const metadata = {
|
const metadata = {
|
||||||
|
@ -126,7 +136,7 @@ export const doPublish = (params: PublishParams) => (dispatch: Dispatch, getStat
|
||||||
|
|
||||||
const publishPayload = {
|
const publishPayload = {
|
||||||
name,
|
name,
|
||||||
channel_name: channelName,
|
channel_id: channelId,
|
||||||
bid,
|
bid,
|
||||||
metadata,
|
metadata,
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import * as ACTIONS from 'constants/action_types';
|
import * as ACTIONS from 'constants/action_types';
|
||||||
import Lbryio from 'lbryio';
|
import Lbryio from 'lbryio';
|
||||||
import { doNotify, MODALS } from 'lbry-redux';
|
import { doNotify, MODALS } from 'lbry-redux';
|
||||||
import { selectUnclaimedRewardsByType } from 'redux/selectors/rewards';
|
import { selectUnclaimedRewards } from 'redux/selectors/rewards';
|
||||||
import { selectUserIsRewardApproved } from 'redux/selectors/user';
|
import { selectUserIsRewardApproved } from 'redux/selectors/user';
|
||||||
import rewards from 'rewards';
|
import rewards from 'rewards';
|
||||||
|
|
||||||
|
@ -30,8 +30,8 @@ export function doRewardList() {
|
||||||
export function doClaimRewardType(rewardType) {
|
export function doClaimRewardType(rewardType) {
|
||||||
return (dispatch, getState) => {
|
return (dispatch, getState) => {
|
||||||
const state = getState();
|
const state = getState();
|
||||||
const rewardsByType = selectUnclaimedRewardsByType(state);
|
const unclaimedRewards = selectUnclaimedRewards(state);
|
||||||
const reward = rewardsByType[rewardType];
|
const reward = unclaimedRewards.find(ur => ur.reward_type === rewardType);
|
||||||
const userIsRewardApproved = selectUserIsRewardApproved(state);
|
const userIsRewardApproved = selectUserIsRewardApproved(state);
|
||||||
|
|
||||||
if (!reward || reward.transaction_id) {
|
if (!reward || reward.transaction_id) {
|
||||||
|
@ -84,14 +84,14 @@ export function doClaimRewardType(rewardType) {
|
||||||
export function doClaimEligiblePurchaseRewards() {
|
export function doClaimEligiblePurchaseRewards() {
|
||||||
return (dispatch, getState) => {
|
return (dispatch, getState) => {
|
||||||
const state = getState();
|
const state = getState();
|
||||||
const rewardsByType = selectUnclaimedRewardsByType(state);
|
const unclaimedRewards = selectUnclaimedRewards(state);
|
||||||
const userIsRewardApproved = selectUserIsRewardApproved(state);
|
const userIsRewardApproved = selectUserIsRewardApproved(state);
|
||||||
|
|
||||||
if (!userIsRewardApproved || !Lbryio.enabled) {
|
if (!userIsRewardApproved || !Lbryio.enabled) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rewardsByType[rewards.TYPE_FIRST_STREAM]) {
|
if (unclaimedRewards.find(ur => ur.reward_type === rewards.TYPE_FIRST_STREAM)) {
|
||||||
dispatch(doClaimRewardType(rewards.TYPE_FIRST_STREAM));
|
dispatch(doClaimRewardType(rewards.TYPE_FIRST_STREAM));
|
||||||
} else {
|
} else {
|
||||||
[rewards.TYPE_MANY_DOWNLOADS, rewards.TYPE_FEATURED_DOWNLOAD].forEach(type => {
|
[rewards.TYPE_MANY_DOWNLOADS, rewards.TYPE_FEATURED_DOWNLOAD].forEach(type => {
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
// @flow
|
// @flow
|
||||||
|
|
||||||
import * as ACTIONS from 'constants/action_types';
|
import * as ACTIONS from 'constants/action_types';
|
||||||
import { MODALS } from 'lbry-redux';
|
|
||||||
|
|
||||||
import { remote } from 'electron';
|
import { remote } from 'electron';
|
||||||
|
|
||||||
|
@ -74,7 +73,6 @@ reducers[ACTIONS.DAEMON_VERSION_MATCH] = state =>
|
||||||
reducers[ACTIONS.DAEMON_VERSION_MISMATCH] = state =>
|
reducers[ACTIONS.DAEMON_VERSION_MISMATCH] = state =>
|
||||||
Object.assign({}, state, {
|
Object.assign({}, state, {
|
||||||
daemonVersionMatched: false,
|
daemonVersionMatched: false,
|
||||||
modal: MODALS.INCOMPATIBLE_DAEMON,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
reducers[ACTIONS.UPGRADE_CANCELLED] = state =>
|
reducers[ACTIONS.UPGRADE_CANCELLED] = state =>
|
||||||
|
|
|
@ -18,6 +18,7 @@ type PublishState = {
|
||||||
language: string,
|
language: string,
|
||||||
tosAccepted: boolean,
|
tosAccepted: boolean,
|
||||||
channel: string,
|
channel: string,
|
||||||
|
channelId: ?string,
|
||||||
name: string,
|
name: string,
|
||||||
nameError: ?string,
|
nameError: ?string,
|
||||||
bid: number,
|
bid: number,
|
||||||
|
@ -41,6 +42,7 @@ export type UpdatePublishFormData = {
|
||||||
language?: string,
|
language?: string,
|
||||||
tosAccepted?: boolean,
|
tosAccepted?: boolean,
|
||||||
channel?: string,
|
channel?: string,
|
||||||
|
channelId?: string,
|
||||||
name?: string,
|
name?: string,
|
||||||
nameError?: string,
|
nameError?: string,
|
||||||
bid?: number,
|
bid?: number,
|
||||||
|
@ -66,6 +68,7 @@ export type PublishParams = {
|
||||||
thumbnail: ?string,
|
thumbnail: ?string,
|
||||||
nsfw: boolean,
|
nsfw: boolean,
|
||||||
channel: string,
|
channel: string,
|
||||||
|
channelId: string,
|
||||||
title: string,
|
title: string,
|
||||||
contentIsFree: boolean,
|
contentIsFree: boolean,
|
||||||
uri: string,
|
uri: string,
|
||||||
|
@ -97,6 +100,7 @@ const defaultState: PublishState = {
|
||||||
language: 'en',
|
language: 'en',
|
||||||
nsfw: false,
|
nsfw: false,
|
||||||
channel: CHANNEL_ANONYMOUS,
|
channel: CHANNEL_ANONYMOUS,
|
||||||
|
channelId: '',
|
||||||
tosAccepted: false,
|
tosAccepted: false,
|
||||||
name: '',
|
name: '',
|
||||||
nameError: undefined,
|
nameError: undefined,
|
||||||
|
|
|
@ -4,7 +4,7 @@ const reducers = {};
|
||||||
const defaultState = {
|
const defaultState = {
|
||||||
fetching: false,
|
fetching: false,
|
||||||
claimedRewardsById: {}, // id => reward
|
claimedRewardsById: {}, // id => reward
|
||||||
unclaimedRewardsByType: {},
|
unclaimedRewards: [],
|
||||||
claimPendingByType: {},
|
claimPendingByType: {},
|
||||||
claimErrorsByType: {},
|
claimErrorsByType: {},
|
||||||
};
|
};
|
||||||
|
@ -17,19 +17,19 @@ reducers[ACTIONS.FETCH_REWARDS_STARTED] = state =>
|
||||||
reducers[ACTIONS.FETCH_REWARDS_COMPLETED] = (state, action) => {
|
reducers[ACTIONS.FETCH_REWARDS_COMPLETED] = (state, action) => {
|
||||||
const { userRewards } = action.data;
|
const { userRewards } = action.data;
|
||||||
|
|
||||||
const unclaimedRewards = {};
|
const unclaimedRewards = [];
|
||||||
const claimedRewards = {};
|
const claimedRewards = {};
|
||||||
userRewards.forEach(reward => {
|
userRewards.forEach(reward => {
|
||||||
if (reward.transaction_id) {
|
if (reward.transaction_id) {
|
||||||
claimedRewards[reward.id] = reward;
|
claimedRewards[reward.id] = reward;
|
||||||
} else {
|
} else {
|
||||||
unclaimedRewards[reward.reward_type] = reward;
|
unclaimedRewards.push(reward);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
return Object.assign({}, state, {
|
return Object.assign({}, state, {
|
||||||
claimedRewardsById: claimedRewards,
|
claimedRewardsById: claimedRewards,
|
||||||
unclaimedRewardsByType: unclaimedRewards,
|
unclaimedRewards,
|
||||||
fetching: false,
|
fetching: false,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
@ -62,24 +62,21 @@ reducers[ACTIONS.CLAIM_REWARD_STARTED] = (state, action) => {
|
||||||
|
|
||||||
reducers[ACTIONS.CLAIM_REWARD_SUCCESS] = (state, action) => {
|
reducers[ACTIONS.CLAIM_REWARD_SUCCESS] = (state, action) => {
|
||||||
const { reward } = action.data;
|
const { reward } = action.data;
|
||||||
|
const { unclaimedRewards } = state;
|
||||||
|
|
||||||
const unclaimedRewardsByType = Object.assign({}, state.unclaimedRewardsByType);
|
const index = unclaimedRewards.findIndex(ur => ur.reward_type === reward.reward_type);
|
||||||
const existingReward = unclaimedRewardsByType[reward.reward_type];
|
unclaimedRewards.splice(index, 1);
|
||||||
|
|
||||||
const newReward = Object.assign({}, reward, {
|
const { claimedRewardsById } = state;
|
||||||
reward_title: existingReward.reward_title,
|
claimedRewardsById[reward.id] = reward;
|
||||||
reward_description: existingReward.reward_description,
|
|
||||||
});
|
|
||||||
|
|
||||||
const claimedRewardsById = Object.assign({}, state.claimedRewardsById);
|
const newState = {
|
||||||
claimedRewardsById[reward.id] = newReward;
|
...state,
|
||||||
|
unclaimedRewards: [...unclaimedRewards],
|
||||||
|
claimedRewardsById: { ...claimedRewardsById },
|
||||||
|
};
|
||||||
|
|
||||||
const newState = Object.assign({}, state, {
|
return setClaimRewardState(newState, reward, false, '');
|
||||||
unclaimedRewardsByType,
|
|
||||||
claimedRewardsById,
|
|
||||||
});
|
|
||||||
|
|
||||||
return setClaimRewardState(newState, newReward, false, '');
|
|
||||||
};
|
};
|
||||||
|
|
||||||
reducers[ACTIONS.CLAIM_REWARD_FAILURE] = (state, action) => {
|
reducers[ACTIONS.CLAIM_REWARD_FAILURE] = (state, action) => {
|
||||||
|
|
|
@ -24,7 +24,7 @@ const defaultState = {
|
||||||
theme: getLocalStorageSetting(SETTINGS.THEME, 'light'),
|
theme: getLocalStorageSetting(SETTINGS.THEME, 'light'),
|
||||||
themes: getLocalStorageSetting(SETTINGS.THEMES, []),
|
themes: getLocalStorageSetting(SETTINGS.THEMES, []),
|
||||||
automaticDarkModeEnabled: getLocalStorageSetting(SETTINGS.AUTOMATIC_DARK_MODE_ENABLED, false),
|
automaticDarkModeEnabled: getLocalStorageSetting(SETTINGS.AUTOMATIC_DARK_MODE_ENABLED, false),
|
||||||
autoplay: getLocalStorageSetting(SETTINGS.AUTOPLAY, false)
|
autoplay: getLocalStorageSetting(SETTINGS.AUTOPLAY, false),
|
||||||
},
|
},
|
||||||
isNight: false,
|
isNight: false,
|
||||||
languages: {},
|
languages: {},
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
import { createSelector } from 'reselect';
|
import { createSelector } from 'reselect';
|
||||||
import REWARDS from 'rewards';
|
|
||||||
|
|
||||||
const selectState = state => state.rewards || {};
|
const selectState = state => state.rewards || {};
|
||||||
|
|
||||||
|
@ -26,16 +25,7 @@ export const selectClaimedRewardsByTransactionId = createSelector(selectClaimedR
|
||||||
}, {})
|
}, {})
|
||||||
);
|
);
|
||||||
|
|
||||||
export const selectUnclaimedRewards = createSelector(
|
export const selectUnclaimedRewards = createSelector(selectState, state => state.unclaimedRewards);
|
||||||
selectUnclaimedRewardsByType,
|
|
||||||
byType =>
|
|
||||||
Object.values(byType).sort(
|
|
||||||
(a, b) =>
|
|
||||||
REWARDS.SORT_ORDER.indexOf(a.reward_type) < REWARDS.SORT_ORDER.indexOf(b.reward_type)
|
|
||||||
? -1
|
|
||||||
: 1
|
|
||||||
) || []
|
|
||||||
);
|
|
||||||
|
|
||||||
export const selectFetchingRewards = createSelector(selectState, state => !!state.fetching);
|
export const selectFetchingRewards = createSelector(selectState, state => !!state.fetching);
|
||||||
|
|
||||||
|
@ -65,7 +55,8 @@ const selectClaimRewardError = (state, props) =>
|
||||||
export const makeSelectClaimRewardError = () =>
|
export const makeSelectClaimRewardError = () =>
|
||||||
createSelector(selectClaimRewardError, errorMessage => errorMessage);
|
createSelector(selectClaimRewardError, errorMessage => errorMessage);
|
||||||
|
|
||||||
const selectRewardByType = (state, props) => selectUnclaimedRewardsByType(state)[props.reward_type];
|
const selectRewardByType = (state, rewardType) =>
|
||||||
|
selectUnclaimedRewards(state).find(reward => reward.reward_type === rewardType);
|
||||||
|
|
||||||
export const makeSelectRewardByType = () => createSelector(selectRewardByType, reward => reward);
|
export const makeSelectRewardByType = () => createSelector(selectRewardByType, reward => reward);
|
||||||
|
|
||||||
|
|
|
@ -1,21 +1,6 @@
|
||||||
import { Lbry, doNotify } from 'lbry-redux';
|
import { Lbry, doNotify } from 'lbry-redux';
|
||||||
import Lbryio from 'lbryio';
|
import Lbryio from 'lbryio';
|
||||||
|
|
||||||
function rewardMessage(type, amount) {
|
|
||||||
return {
|
|
||||||
new_developer: __('You earned %s for registering as a new developer.', amount),
|
|
||||||
new_user: __('You earned %s LBC new user reward.', amount),
|
|
||||||
verified_email: __('You earned %s LBC for verifying your email address.', amount),
|
|
||||||
new_channel: __('You earned %s LBC for creating a publisher identity.', amount),
|
|
||||||
first_stream: __('You earned %s LBC for streaming your first video.', amount),
|
|
||||||
many_downloads: __('You earned %s LBC for downloading a bunch of things.', amount),
|
|
||||||
first_publish: __('You earned %s LBC for making your first publication.', amount),
|
|
||||||
featured_download: __('You earned %s LBC for watching a featured download.', amount),
|
|
||||||
referral: __('You earned %s LBC for referring someone.', amount),
|
|
||||||
youtube_creator: __('You earned %s LBC for syncing your YouTube channel.', amount),
|
|
||||||
}[type];
|
|
||||||
}
|
|
||||||
|
|
||||||
const rewards = {};
|
const rewards = {};
|
||||||
|
|
||||||
rewards.TYPE_NEW_DEVELOPER = 'new_developer';
|
rewards.TYPE_NEW_DEVELOPER = 'new_developer';
|
||||||
|
@ -28,18 +13,6 @@ rewards.TYPE_FIRST_PUBLISH = 'first_publish';
|
||||||
rewards.TYPE_FEATURED_DOWNLOAD = 'featured_download';
|
rewards.TYPE_FEATURED_DOWNLOAD = 'featured_download';
|
||||||
rewards.TYPE_REFERRAL = 'referral';
|
rewards.TYPE_REFERRAL = 'referral';
|
||||||
rewards.YOUTUBE_CREATOR = 'youtube_creator';
|
rewards.YOUTUBE_CREATOR = 'youtube_creator';
|
||||||
rewards.SORT_ORDER = [
|
|
||||||
rewards.TYPE_NEW_USER,
|
|
||||||
rewards.TYPE_CONFIRM_EMAIL,
|
|
||||||
rewards.TYPE_FIRST_STREAM,
|
|
||||||
rewards.TYPE_FIRST_CHANNEL,
|
|
||||||
rewards.TYPE_FIRST_PUBLISH,
|
|
||||||
rewards.TYPE_FEATURED_DOWNLOAD,
|
|
||||||
rewards.TYPE_MANY_DOWNLOADS,
|
|
||||||
rewards.TYPE_REFERRAL,
|
|
||||||
rewards.TYPE_NEW_DEVELOPER,
|
|
||||||
rewards.YOUTUBE_CREATOR,
|
|
||||||
];
|
|
||||||
|
|
||||||
rewards.claimReward = type => {
|
rewards.claimReward = type => {
|
||||||
function requestReward(resolve, reject, params) {
|
function requestReward(resolve, reject, params) {
|
||||||
|
@ -48,7 +21,8 @@ rewards.claimReward = type => {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Lbryio.call('reward', 'new', params, 'post').then(reward => {
|
Lbryio.call('reward', 'new', params, 'post').then(reward => {
|
||||||
const message = rewardMessage(type, reward.reward_amount);
|
const message =
|
||||||
|
reward.reward_notification || `You have claimed a ${reward.reward_amount} LBC reward.`;
|
||||||
|
|
||||||
// Display global notice
|
// Display global notice
|
||||||
const action = doNotify({
|
const action = doNotify({
|
||||||
|
@ -56,6 +30,7 @@ rewards.claimReward = type => {
|
||||||
linkText: __('Show All'),
|
linkText: __('Show All'),
|
||||||
linkTarget: '/rewards',
|
linkTarget: '/rewards',
|
||||||
isError: false,
|
isError: false,
|
||||||
|
displayType: ['snackbar'],
|
||||||
});
|
});
|
||||||
window.app.store.dispatch(action);
|
window.app.store.dispatch(action);
|
||||||
|
|
||||||
|
|
|
@ -259,6 +259,7 @@ p {
|
||||||
font-family: 'metropolis-bold';
|
font-family: 'metropolis-bold';
|
||||||
font-size: 10px;
|
font-size: 10px;
|
||||||
padding: 5px;
|
padding: 5px;
|
||||||
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
.credit-amount--large {
|
.credit-amount--large {
|
||||||
|
|
|
@ -12,6 +12,7 @@ $large-breakpoint: 1760px;
|
||||||
--side-nav-width: 220px;
|
--side-nav-width: 220px;
|
||||||
--side-nav-width-m: 240px;
|
--side-nav-width-m: 240px;
|
||||||
--side-nav-width-l: 320px;
|
--side-nav-width-l: 320px;
|
||||||
|
--font-size-subtext-multiple: 0.92;
|
||||||
|
|
||||||
--video-aspect-ratio: 56.25%; // 9 x 16
|
--video-aspect-ratio: 56.25%; // 9 x 16
|
||||||
--snack-bar-width: 756px;
|
--snack-bar-width: 756px;
|
||||||
|
@ -35,6 +36,7 @@ $large-breakpoint: 1760px;
|
||||||
--color-green-light: #effbe4;
|
--color-green-light: #effbe4;
|
||||||
--color-green-blue: #2ec1a8;
|
--color-green-blue: #2ec1a8;
|
||||||
--color-purple: #8165b0;
|
--color-purple: #8165b0;
|
||||||
|
--color-blue-grey: #203049;
|
||||||
|
|
||||||
/* Colors */
|
/* Colors */
|
||||||
--color-divider: #e3e3e3;
|
--color-divider: #e3e3e3;
|
||||||
|
@ -73,6 +75,8 @@ $large-breakpoint: 1760px;
|
||||||
--input-copyable-bg: #f6f6f6;
|
--input-copyable-bg: #f6f6f6;
|
||||||
--input-copyable-color: var(--color-grey-dark);
|
--input-copyable-color: var(--color-grey-dark);
|
||||||
--input-copyable-border: var(--color-grey);
|
--input-copyable-border: var(--color-grey);
|
||||||
|
--input-select-bg-color: var(--color-grey);
|
||||||
|
--input-select-color: var(--text-color);
|
||||||
|
|
||||||
/* input:disabled */
|
/* input:disabled */
|
||||||
--input-disabled-border-color: rgba(0, 0, 0, 0.42);
|
--input-disabled-border-color: rgba(0, 0, 0, 0.42);
|
||||||
|
@ -146,7 +150,8 @@ $large-breakpoint: 1760px;
|
||||||
--success-msg-bg: var(--color-green-light);
|
--success-msg-bg: var(--color-green-light);
|
||||||
|
|
||||||
/* File Tile Card */
|
/* File Tile Card */
|
||||||
--file-tile--media-size: 60px;
|
--file-tile--media-height: 100px;
|
||||||
|
--file-tile--media-width: calc(100px * (1 + 9 / 16));
|
||||||
|
|
||||||
/* Modal */
|
/* Modal */
|
||||||
--modal-width: 440px;
|
--modal-width: 440px;
|
||||||
|
@ -157,9 +162,8 @@ $large-breakpoint: 1760px;
|
||||||
--modal-btn-bg-color: var(--btn-bg-alt);
|
--modal-btn-bg-color: var(--btn-bg-alt);
|
||||||
|
|
||||||
// /* Tooltip */
|
// /* Tooltip */
|
||||||
--tooltip-width: 300px;
|
--tooltip-bg: #555;
|
||||||
--tooltip-bg: var(--color-bg);
|
--tooltip-color: var(--color-white);
|
||||||
--tooltip-color: var(--text-color);
|
|
||||||
|
|
||||||
/* Scrollbar */
|
/* Scrollbar */
|
||||||
--scrollbar-radius: 10px;
|
--scrollbar-radius: 10px;
|
||||||
|
|
|
@ -145,10 +145,7 @@ button:disabled {
|
||||||
|
|
||||||
.btn.btn--arrow {
|
.btn.btn--arrow {
|
||||||
width: var(--btn-arrow-width);
|
width: var(--btn-arrow-width);
|
||||||
|
color: var(--text-color);
|
||||||
&:hover:not(:disabled) {
|
|
||||||
color: var(--text-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
&:disabled {
|
&:disabled {
|
||||||
opacity: 0.3;
|
opacity: 0.3;
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
margin-left: auto;
|
margin-left: auto;
|
||||||
margin-right: auto;
|
margin-right: auto;
|
||||||
border-radius: var(--card-radius);
|
border-radius: var(--card-radius);
|
||||||
overflow: auto;
|
|
||||||
user-select: text;
|
user-select: text;
|
||||||
display: flex;
|
display: flex;
|
||||||
position: relative;
|
position: relative;
|
||||||
|
@ -18,7 +17,6 @@
|
||||||
|
|
||||||
.card--small {
|
.card--small {
|
||||||
width: var(--card-small-width);
|
width: var(--card-small-width);
|
||||||
overflow-x: hidden;
|
|
||||||
white-space: normal;
|
white-space: normal;
|
||||||
|
|
||||||
.card__media {
|
.card__media {
|
||||||
|
@ -87,8 +85,7 @@
|
||||||
align-items: center;
|
align-items: center;
|
||||||
.credit-amount,
|
.credit-amount,
|
||||||
.icon {
|
.icon {
|
||||||
margin-top: $spacing-vertical * 1/3;
|
margin: $spacing-vertical * 1/3;
|
||||||
margin-left: $spacing-vertical * 2/3;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -103,13 +100,6 @@
|
||||||
color: var(--text-color);
|
color: var(--text-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
.card__title--file {
|
|
||||||
font-family: 'metropolis-bold';
|
|
||||||
font-size: 28px;
|
|
||||||
line-height: 36px;
|
|
||||||
padding-top: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.card__title--small {
|
.card__title--small {
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
line-height: 18px;
|
line-height: 18px;
|
||||||
|
@ -117,23 +107,31 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.card__title--file {
|
.card__title--file {
|
||||||
|
font-family: 'metropolis-bold';
|
||||||
|
font-size: 28px;
|
||||||
|
margin-bottom: 0;
|
||||||
padding-top: 0;
|
padding-top: 0;
|
||||||
padding-bottom: 5px;
|
padding-bottom: 5px;
|
||||||
|
font-size: 18px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.card__subtitle {
|
.card__subtitle {
|
||||||
|
margin: 0;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
font-family: 'metropolis-medium';
|
font-family: 'metropolis-medium';
|
||||||
color: var(--card-text-color);
|
color: var(--card-text-color);
|
||||||
|
|
||||||
.icon {
|
.icon {
|
||||||
margin-left: $spacing-vertical * 1/3;
|
margin-top: $spacing-vertical * 1/6;
|
||||||
|
|
||||||
|
&:not(:first-of-type) {
|
||||||
|
margin: 0 $spacing-vertical * 1/3;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.card__subtitle--file-info {
|
.card__subtitle-price {
|
||||||
display: flex;
|
padding-top: $spacing-vertical * 1/3;
|
||||||
align-items: center;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.card__subtitle--block {
|
.card__subtitle--block {
|
||||||
|
@ -180,6 +178,10 @@
|
||||||
margin-top: $spacing-vertical * 2/3;
|
margin-top: $spacing-vertical * 2/3;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.card__content--extra-padding {
|
||||||
|
margin-top: $spacing-vertical;
|
||||||
|
}
|
||||||
|
|
||||||
.card__subtext-title {
|
.card__subtext-title {
|
||||||
color: var(--text-color);
|
color: var(--text-color);
|
||||||
font-size: calc(var(--font-size-subtext-multiple) * 1.5em);
|
font-size: calc(var(--font-size-subtext-multiple) * 1.5em);
|
||||||
|
@ -194,7 +196,10 @@
|
||||||
padding-top: $spacing-vertical * 1/3;
|
padding-top: $spacing-vertical * 1/3;
|
||||||
word-break: break-word;
|
word-break: break-word;
|
||||||
font-family: 'metropolis-medium';
|
font-family: 'metropolis-medium';
|
||||||
font-size: 13px;
|
}
|
||||||
|
|
||||||
|
.card__subtext--small {
|
||||||
|
font-size: calc(var(--font-size-subtext-multiple) * 0.8em);
|
||||||
}
|
}
|
||||||
|
|
||||||
.card__actions {
|
.card__actions {
|
||||||
|
@ -236,12 +241,11 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
.card-row is used on the discover/subscriptions page
|
.card-row is used on the discover page
|
||||||
It is a list of cards that extend past the right edge of the screen
|
It is a list of cards that extend past the right edge of the screen
|
||||||
There are left/right arrows to scroll the cards and view hidden content
|
There are left/right arrows to scroll the cards and view hidden content
|
||||||
*/
|
*/
|
||||||
.card-row {
|
.card-row {
|
||||||
overflow: hidden;
|
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
min-width: var(--card-small-width);
|
min-width: var(--card-small-width);
|
||||||
|
@ -282,6 +286,18 @@
|
||||||
padding-top: $spacing-vertical * 2/3;
|
padding-top: $spacing-vertical * 2/3;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
|
||||||
|
.card {
|
||||||
|
display: inline-block;
|
||||||
|
vertical-align: top;
|
||||||
|
overflow-y: visible;
|
||||||
|
// 31 px to handle to padding between cards
|
||||||
|
width: calc((100% / 4) - 31px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.card:not(:first-of-type) {
|
||||||
|
margin-left: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
.card:first-of-type {
|
.card:first-of-type {
|
||||||
margin-left: $spacing-width;
|
margin-left: $spacing-width;
|
||||||
}
|
}
|
||||||
|
@ -320,27 +336,6 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.card-row__scrollhouse {
|
|
||||||
padding-top: $spacing-vertical * 2/3;
|
|
||||||
overflow: hidden;
|
|
||||||
|
|
||||||
.card {
|
|
||||||
display: inline-block;
|
|
||||||
vertical-align: top;
|
|
||||||
overflow: visible;
|
|
||||||
// 31 px to handle to padding between cards
|
|
||||||
width: calc((100% / 4) - 31px);
|
|
||||||
}
|
|
||||||
|
|
||||||
.card:not(:first-of-type) {
|
|
||||||
margin-left: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.card:last-of-type {
|
|
||||||
margin-right: 20px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.card__success-msg {
|
.card__success-msg {
|
||||||
border-left: 2px solid var(--success-msg-border);
|
border-left: 2px solid var(--success-msg-border);
|
||||||
color: var(--success-msg-color);
|
color: var(--success-msg-color);
|
||||||
|
|
|
@ -1,26 +1,3 @@
|
||||||
.file-download,
|
|
||||||
.file-download__overlay {
|
|
||||||
padding: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.file-download {
|
.file-download {
|
||||||
position: relative;
|
font-size: 0.8em;
|
||||||
background-color: var(--color-black);
|
|
||||||
border-radius: var(--btn-radius);
|
|
||||||
color: var(--color-download);
|
|
||||||
font-size: 12px;
|
|
||||||
opacity: 0.8;
|
|
||||||
font-family: 'metropolis-medium';
|
|
||||||
}
|
|
||||||
|
|
||||||
.file-download__overlay {
|
|
||||||
background: var(--color-download);
|
|
||||||
color: var(--color-download-overlay);
|
|
||||||
border-radius: var(--btn-radius);
|
|
||||||
position: absolute;
|
|
||||||
white-space: nowrap;
|
|
||||||
overflow: hidden;
|
|
||||||
z-index: 1;
|
|
||||||
top: 0px;
|
|
||||||
left: 0px;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,17 +13,20 @@
|
||||||
|
|
||||||
.file-list__header {
|
.file-list__header {
|
||||||
margin-top: $spacing-vertical * 4/3;
|
margin-top: $spacing-vertical * 4/3;
|
||||||
font-size: 18px;
|
font-size: 24px;
|
||||||
|
|
||||||
|
.tooltip {
|
||||||
|
margin-left: 5px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.file-tile {
|
.file-tile {
|
||||||
display: flex;
|
display: flex;
|
||||||
margin-top: $spacing-vertical;
|
margin-top: $spacing-vertical;
|
||||||
max-width: 260px;
|
|
||||||
height: var(--file-tile--media-size);
|
|
||||||
|
|
||||||
.card__media {
|
.card__media {
|
||||||
flex: 0 0 var(--file-tile--media-size);
|
height: var(--file-tile--media-height);
|
||||||
|
flex: 0 0 var(--file-tile--media-width);
|
||||||
}
|
}
|
||||||
|
|
||||||
.card__subtitle {
|
.card__subtitle {
|
||||||
|
@ -36,7 +39,10 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.file-tile__info {
|
.file-tile__info {
|
||||||
margin-left: $spacing-vertical * 1/3;
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
margin-left: $spacing-vertical * 2/3;
|
||||||
|
max-width: 500px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.file-tile__uri {
|
.file-tile__uri {
|
||||||
|
|
|
@ -62,6 +62,10 @@
|
||||||
width: 35px;
|
width: 35px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
input.paginate-channel {
|
||||||
|
width: 35px;
|
||||||
|
}
|
||||||
|
|
||||||
&.form-field--auto-height {
|
&.form-field--auto-height {
|
||||||
height: auto;
|
height: auto;
|
||||||
}
|
}
|
||||||
|
@ -100,10 +104,23 @@
|
||||||
padding-left: $spacing-vertical * 1/3;
|
padding-left: $spacing-vertical * 1/3;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.form-field__select {
|
||||||
|
min-width: 60px;
|
||||||
|
height: 30px;
|
||||||
|
border-radius: 8px;
|
||||||
|
background-color: var(--input-select-bg-color);
|
||||||
|
font: normal 12px/30px 'metropolis-medium';
|
||||||
|
color: var(--input-select-color);
|
||||||
|
|
||||||
|
&:disabled {
|
||||||
|
opacity: 0.5;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Not sure if I like these
|
// Not sure if I like these
|
||||||
// Maybe this should be in gui.scss?
|
// Maybe this should be in gui.scss?
|
||||||
.input--price-amount {
|
.input--price-amount {
|
||||||
width: 60px;
|
width: 80px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.input--address {
|
.input--address {
|
||||||
|
|
|
@ -45,8 +45,9 @@ div.editor-toolbar a {
|
||||||
}
|
}
|
||||||
|
|
||||||
.editor-preview {
|
.editor-preview {
|
||||||
background: var(--card-bg) !important;
|
font-size: calc(var(--font-size-subtext-multiple) * 1em);
|
||||||
border: 0 !important;
|
background: var(--color-bg) !important;
|
||||||
|
border: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.editor-preview-side {
|
.editor-preview-side {
|
||||||
|
@ -54,18 +55,6 @@ div.editor-toolbar a {
|
||||||
border: 1px solid var(--input-border-color) !important;
|
border: 1px solid var(--input-border-color) !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.editor-preview pre,
|
|
||||||
.editor-preview-side pre {
|
|
||||||
background: #eee;
|
|
||||||
}
|
|
||||||
|
|
||||||
.editor-preview table td,
|
|
||||||
.editor-preview table th,
|
|
||||||
.editor-preview-side table td,
|
|
||||||
.editor-preview-side table th {
|
|
||||||
border: 1px solid var(--input-border-color) !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.CodeMirror .CodeMirror-code .cm-tag {
|
.CodeMirror .CodeMirror-code .cm-tag {
|
||||||
color: #63a35c;
|
color: #63a35c;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
|
.editor-preview,
|
||||||
.markdown-preview {
|
.markdown-preview {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
|
|
||||||
/* Headings: title */
|
/* Headers */
|
||||||
|
|
||||||
h1,
|
h1,
|
||||||
h2,
|
h2,
|
||||||
h3,
|
h3,
|
||||||
|
@ -37,39 +37,48 @@
|
||||||
font-size: 0.84em;
|
font-size: 0.84em;
|
||||||
color: var(--color-help);
|
color: var(--color-help);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
.markdown-preview table {
|
/* Paragraphs */
|
||||||
padding: 8px;
|
p {
|
||||||
margin: 16px 0;
|
white-space: pre-line;
|
||||||
background-color: var(--card-bg);
|
|
||||||
|
|
||||||
tr td,
|
|
||||||
tr th,
|
|
||||||
tr td:first-of-type,
|
|
||||||
tr th:first-of-type,
|
|
||||||
tr td:last-of-type,
|
|
||||||
tr th:last-of-type {
|
|
||||||
padding: 8px;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
.markdown-preview code {
|
/* Strikethrough text */
|
||||||
display: block;
|
del {
|
||||||
padding: 8px;
|
color: var(--color-help);
|
||||||
margin: 16px 0;
|
}
|
||||||
background-color: var(--color-bg-alt);
|
|
||||||
color: var(--color-help);
|
|
||||||
font-size: 1em;
|
|
||||||
font-family: Consolas, 'Lucida Console', 'Source Sans', monospace;
|
|
||||||
}
|
|
||||||
|
|
||||||
.markdown-preview hr {
|
/* Tables */
|
||||||
border: 1px solid var(--color-divider);
|
table {
|
||||||
}
|
padding: 8px;
|
||||||
|
margin: 16px 0;
|
||||||
|
background-color: var(--card-bg);
|
||||||
|
|
||||||
.markdown-preview del {
|
tr td,
|
||||||
color: var(--color-help);
|
tr th,
|
||||||
|
tr td:first-of-type,
|
||||||
|
tr th:first-of-type,
|
||||||
|
tr td:last-of-type,
|
||||||
|
tr th:last-of-type {
|
||||||
|
padding: 8px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Horizontal Rule */
|
||||||
|
hr {
|
||||||
|
border: 1px solid var(--color-divider);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Code */
|
||||||
|
code {
|
||||||
|
display: block;
|
||||||
|
padding: 8px;
|
||||||
|
margin: 16px 0;
|
||||||
|
background-color: var(--color-bg-alt);
|
||||||
|
color: var(--color-help);
|
||||||
|
font-size: 1em;
|
||||||
|
font-family: Consolas, 'Lucida Console', 'Source Sans', monospace;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
blockquote {
|
blockquote {
|
||||||
|
|
|
@ -81,28 +81,15 @@
|
||||||
background-color: var(--color-secondary);
|
background-color: var(--color-secondary);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Search modal
|
|
||||||
// Input field used inside search modal
|
|
||||||
.search__wrapper {
|
|
||||||
height: var(--search-modal-input-height);
|
|
||||||
}
|
|
||||||
|
|
||||||
.search__input {
|
|
||||||
font-family: 'metropolis-bold';
|
|
||||||
font-size: var(--search-modal-input-height);
|
|
||||||
color: var(--search-color);
|
|
||||||
background: transparent;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.search__results {
|
.search__results {
|
||||||
display: flex;
|
|
||||||
padding-bottom: $spacing-vertical;
|
padding-bottom: $spacing-vertical;
|
||||||
|
flex-flow: wrap column;
|
||||||
|
|
||||||
.search-result__column {
|
.search-result__row {
|
||||||
flex: 0 0 270px;
|
padding: $spacing-vertical 0;
|
||||||
.card__media {
|
|
||||||
background-color: var(--color-search-placeholder);
|
&:first-of-type {
|
||||||
|
padding-top: 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
table.table,
|
table.table,
|
||||||
|
.editor-preview table,
|
||||||
.markdown-preview table {
|
.markdown-preview table {
|
||||||
word-wrap: break-word;
|
word-wrap: break-word;
|
||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
|
@ -28,6 +29,7 @@ table.table,
|
||||||
|
|
||||||
th {
|
th {
|
||||||
font-family: 'metropolis-semibold';
|
font-family: 'metropolis-semibold';
|
||||||
|
border: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
td {
|
td {
|
||||||
|
|
|
@ -1,30 +1,97 @@
|
||||||
@import '../mixin/link.scss';
|
|
||||||
|
|
||||||
.tooltip {
|
.tooltip {
|
||||||
position: relative;
|
position: relative;
|
||||||
padding: 0 $spacing-vertical / 3;
|
display: inline-block;
|
||||||
font-size: 12px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.tooltip__body {
|
// When there is a label for the tooltip and not just using a button or icon
|
||||||
|
.tooltip.tooltip--label {
|
||||||
|
font-size: 12px;
|
||||||
|
padding-left: $spacing-vertical * 1/3;
|
||||||
|
|
||||||
|
.tooltip__body {
|
||||||
|
margin-top: 5px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.tooltip.tooltip--icon {
|
||||||
|
margin-top: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Tooltip text */
|
||||||
|
.tooltip .tooltip__body {
|
||||||
|
background-color: var(--tooltip-bg);
|
||||||
|
font-family: 'metropolis-medium';
|
||||||
|
font-size: 12px;
|
||||||
|
color: var(--tooltip-color);
|
||||||
|
border-radius: 8px;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
left: 50%;
|
width: 200px;
|
||||||
margin-left: calc(var(--tooltip-width) * -1 / 2);
|
text-align: center;
|
||||||
white-space: normal;
|
white-space: pre-wrap;
|
||||||
box-sizing: border-box;
|
padding: $spacing-vertical * 1/3;
|
||||||
padding: $spacing-vertical / 2;
|
visibility: hidden;
|
||||||
width: var(--tooltip-width);
|
|
||||||
color: var(--tooltip-color);
|
|
||||||
background-color: var(--tooltip-bg);
|
|
||||||
font-size: calc(var(--font-size) * 7 / 8);
|
|
||||||
line-height: var(--font-line-height);
|
|
||||||
box-shadow: var(--box-shadow-layer);
|
|
||||||
border-radius: var(--card-radius);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.tooltip__link {
|
.tooltip .tooltip__body::after {
|
||||||
font-size: calc(var(--font-size) * 3 / 4);
|
content: ' ';
|
||||||
margin-left: var(--button-padding);
|
width: 0;
|
||||||
vertical-align: middle;
|
height: 0;
|
||||||
|
position: absolute;
|
||||||
|
border-width: 5px;
|
||||||
|
border-style: solid;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tooltip.tooltip--top .tooltip__body {
|
||||||
|
bottom: 100%;
|
||||||
|
left: 50%;
|
||||||
|
margin-left: -100px;
|
||||||
|
|
||||||
|
&::after {
|
||||||
|
top: 100%;
|
||||||
|
left: 50%;
|
||||||
|
margin-left: -5px;
|
||||||
|
border-color: var(--tooltip-bg) transparent transparent transparent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.tooltip.tooltip--right .tooltip__body {
|
||||||
|
margin-top: -5px;
|
||||||
|
margin-left: 10px;
|
||||||
|
|
||||||
|
&::after {
|
||||||
|
top: 17px;
|
||||||
|
right: 100%; /* To the left of the tooltip */
|
||||||
|
margin-top: -5px;
|
||||||
|
border-color: transparent var(--tooltip-bg) transparent transparent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.tooltip.tooltip--bottom .tooltip__body {
|
||||||
|
top: 90%;
|
||||||
|
left: 50%;
|
||||||
|
margin-left: -100px;
|
||||||
|
|
||||||
|
&::after {
|
||||||
|
bottom: 100%;
|
||||||
|
left: 50%;
|
||||||
|
margin-left: -5px;
|
||||||
|
border-color: transparent transparent var(--tooltip-bg) transparent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.tooltip.tooltip--left .tooltip__body {
|
||||||
|
top: -5px;
|
||||||
|
right: 105%;
|
||||||
|
|
||||||
|
&::after {
|
||||||
|
top: 17px;
|
||||||
|
left: 100%;
|
||||||
|
margin-top: -5px;
|
||||||
|
border-color: transparent transparent transparent var(--tooltip-bg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.tooltip:hover .tooltip__body {
|
||||||
|
visibility: visible;
|
||||||
}
|
}
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue