mirror of
https://github.com/zhigang1992/devhub.git
synced 2026-05-29 00:21:04 +08:00
Finished event cards components
This commit is contained in:
@@ -137,6 +137,7 @@ android {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compile project(':react-native-linear-gradient')
|
||||
compile fileTree(dir: "libs", include: ["*.jar"])
|
||||
compile "com.android.support:appcompat-v7:23.0.1"
|
||||
compile "com.facebook.react:react-native:+" // From node_modules
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
rootProject.name = 'devhub'
|
||||
include ':react-native-linear-gradient'
|
||||
project(':react-native-linear-gradient').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-linear-gradient/android')
|
||||
include ':react-native-gesture-handler'
|
||||
project(':react-native-gesture-handler').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-gesture-handler/android')
|
||||
include ':react-native-navigation'
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
00C302E91ABCBA2D00DB3ED1 /* libRCTNetwork.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 00C302DC1ABCB9D200DB3ED1 /* libRCTNetwork.a */; };
|
||||
00C302EA1ABCBA2D00DB3ED1 /* libRCTVibration.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 00C302E41ABCB9EE00DB3ED1 /* libRCTVibration.a */; };
|
||||
00E356F31AD99517003FC87E /* devhubTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 00E356F21AD99517003FC87E /* devhubTests.m */; };
|
||||
072BCFEF97034DD8A762C885 /* libBVLinearGradient.a in Frameworks */ = {isa = PBXBuildFile; fileRef = D59EE38FE98B402B99250666 /* libBVLinearGradient.a */; };
|
||||
133E29F31AD74F7200F7D852 /* libRCTLinking.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 78C398B91ACF4ADC00677621 /* libRCTLinking.a */; };
|
||||
139105C61AF99C1200B5F7CC /* libRCTSettings.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 139105C11AF99BAD00B5F7CC /* libRCTSettings.a */; };
|
||||
139FDEF61B0652A700C62182 /* libRCTWebSocket.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 139FDEF41B06529B00C62182 /* libRCTWebSocket.a */; };
|
||||
@@ -117,6 +118,20 @@
|
||||
remoteGlobalIDString = 2D02E47A1E0B4A5D006451C7;
|
||||
remoteInfo = "devhub-tvOS";
|
||||
};
|
||||
2E60B5072001851A0076D5AF /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = 12697B233D884F2EB9A7D7F0 /* BVLinearGradient.xcodeproj */;
|
||||
proxyType = 2;
|
||||
remoteGlobalIDString = 134814201AA4EA6300B7C361;
|
||||
remoteInfo = BVLinearGradient;
|
||||
};
|
||||
2E60B5092001851A0076D5AF /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = 12697B233D884F2EB9A7D7F0 /* BVLinearGradient.xcodeproj */;
|
||||
proxyType = 2;
|
||||
remoteGlobalIDString = 64AA15081EF7F30100718508;
|
||||
remoteInfo = "BVLinearGradient-tvOS";
|
||||
};
|
||||
2E9757CD1FE54A870087D2A7 /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = D1C1CBC9A5564D089F2E18B2 /* ReactNativeNavigation.xcodeproj */;
|
||||
@@ -346,6 +361,7 @@
|
||||
00E356EE1AD99517003FC87E /* devhubTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = devhubTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
00E356F11AD99517003FC87E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
00E356F21AD99517003FC87E /* devhubTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = devhubTests.m; sourceTree = "<group>"; };
|
||||
12697B233D884F2EB9A7D7F0 /* BVLinearGradient.xcodeproj */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = "wrapper.pb-project"; name = BVLinearGradient.xcodeproj; path = "../node_modules/react-native-linear-gradient/BVLinearGradient.xcodeproj"; sourceTree = "<group>"; };
|
||||
139105B61AF99BAD00B5F7CC /* RCTSettings.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTSettings.xcodeproj; path = "../node_modules/react-native/Libraries/Settings/RCTSettings.xcodeproj"; sourceTree = "<group>"; };
|
||||
139FDEE61B06529A00C62182 /* RCTWebSocket.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTWebSocket.xcodeproj; path = "../node_modules/react-native/Libraries/WebSocket/RCTWebSocket.xcodeproj"; sourceTree = "<group>"; };
|
||||
13B07F961A680F5B00A75B9A /* devhub.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = devhub.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
@@ -376,6 +392,7 @@
|
||||
B6BF65C496E44E78BF211275 /* RNVectorIcons.xcodeproj */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = "wrapper.pb-project"; name = RNVectorIcons.xcodeproj; path = "../node_modules/react-native-vector-icons/RNVectorIcons.xcodeproj"; sourceTree = "<group>"; };
|
||||
C1F790D96FC04CEBA08381F0 /* SafariViewManager.xcodeproj */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = "wrapper.pb-project"; name = SafariViewManager.xcodeproj; path = "../node_modules/react-native-safari-view/SafariViewManager.xcodeproj"; sourceTree = "<group>"; };
|
||||
D1C1CBC9A5564D089F2E18B2 /* ReactNativeNavigation.xcodeproj */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = "wrapper.pb-project"; name = ReactNativeNavigation.xcodeproj; path = "../node_modules/react-native-navigation/ios/ReactNativeNavigation.xcodeproj"; sourceTree = "<group>"; };
|
||||
D59EE38FE98B402B99250666 /* libBVLinearGradient.a */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = archive.ar; path = libBVLinearGradient.a; sourceTree = "<group>"; };
|
||||
D8C408A943574FCE997797CD /* libReactNativeNavigation.a */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = archive.ar; path = libReactNativeNavigation.a; sourceTree = "<group>"; };
|
||||
F035D9E85FA74D8CBFBDAE1B /* SimpleLineIcons.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = SimpleLineIcons.ttf; path = "../node_modules/react-native-vector-icons/Fonts/SimpleLineIcons.ttf"; sourceTree = "<group>"; };
|
||||
F1AA246742BC4C2A8C9988F3 /* Feather.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = Feather.ttf; path = "../node_modules/react-native-vector-icons/Fonts/Feather.ttf"; sourceTree = "<group>"; };
|
||||
@@ -413,6 +430,7 @@
|
||||
C2619E3179B6481FA20E5CEB /* libRNGestureHandler.a in Frameworks */,
|
||||
B71E99D6DCBF4278835E3D03 /* libReactNativeNavigation.a in Frameworks */,
|
||||
DC69E7EC47C64276A45E93CF /* libSafariViewManager.a in Frameworks */,
|
||||
072BCFEF97034DD8A762C885 /* libBVLinearGradient.a in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@@ -555,6 +573,15 @@
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
2E60B5032001851A0076D5AF /* Products */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
2E60B5082001851A0076D5AF /* libBVLinearGradient.a */,
|
||||
2E60B50A2001851A0076D5AF /* libBVLinearGradient.a */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
2E9757CA1FE54A870087D2A7 /* Products */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
@@ -578,6 +605,7 @@
|
||||
B5DF78792708477FB2343101 /* libRNGestureHandler.a */,
|
||||
D8C408A943574FCE997797CD /* libReactNativeNavigation.a */,
|
||||
55B8B3E654F0420CA0ED33D3 /* libSafariViewManager.a */,
|
||||
D59EE38FE98B402B99250666 /* libBVLinearGradient.a */,
|
||||
);
|
||||
name = "Recovered References";
|
||||
sourceTree = "<group>";
|
||||
@@ -635,6 +663,7 @@
|
||||
1FD65CD116F747ACA2D47E1F /* RNGestureHandler.xcodeproj */,
|
||||
D1C1CBC9A5564D089F2E18B2 /* ReactNativeNavigation.xcodeproj */,
|
||||
C1F790D96FC04CEBA08381F0 /* SafariViewManager.xcodeproj */,
|
||||
12697B233D884F2EB9A7D7F0 /* BVLinearGradient.xcodeproj */,
|
||||
);
|
||||
name = Libraries;
|
||||
sourceTree = "<group>";
|
||||
@@ -815,6 +844,10 @@
|
||||
productRefGroup = 83CBBA001A601CBA00E9B192 /* Products */;
|
||||
projectDirPath = "";
|
||||
projectReferences = (
|
||||
{
|
||||
ProductGroup = 2E60B5032001851A0076D5AF /* Products */;
|
||||
ProjectRef = 12697B233D884F2EB9A7D7F0 /* BVLinearGradient.xcodeproj */;
|
||||
},
|
||||
{
|
||||
ProductGroup = 00C302A81ABCB8CE00DB3ED1 /* Products */;
|
||||
ProjectRef = 00C302A71ABCB8CE00DB3ED1 /* RCTActionSheet.xcodeproj */;
|
||||
@@ -947,6 +980,20 @@
|
||||
remoteRef = 146834031AC3E56700842450 /* PBXContainerItemProxy */;
|
||||
sourceTree = BUILT_PRODUCTS_DIR;
|
||||
};
|
||||
2E60B5082001851A0076D5AF /* libBVLinearGradient.a */ = {
|
||||
isa = PBXReferenceProxy;
|
||||
fileType = archive.ar;
|
||||
path = libBVLinearGradient.a;
|
||||
remoteRef = 2E60B5072001851A0076D5AF /* PBXContainerItemProxy */;
|
||||
sourceTree = BUILT_PRODUCTS_DIR;
|
||||
};
|
||||
2E60B50A2001851A0076D5AF /* libBVLinearGradient.a */ = {
|
||||
isa = PBXReferenceProxy;
|
||||
fileType = archive.ar;
|
||||
path = libBVLinearGradient.a;
|
||||
remoteRef = 2E60B5092001851A0076D5AF /* PBXContainerItemProxy */;
|
||||
sourceTree = BUILT_PRODUCTS_DIR;
|
||||
};
|
||||
2E9757CE1FE54A870087D2A7 /* libReactNativeNavigation.a */ = {
|
||||
isa = PBXReferenceProxy;
|
||||
fileType = archive.ar;
|
||||
@@ -1311,6 +1358,7 @@
|
||||
"$(SRCROOT)/../node_modules/react-native-gesture-handler/ios/**",
|
||||
"$(SRCROOT)/../node_modules/react-native-navigation/ios/**",
|
||||
"$(SRCROOT)/../node_modules/react-native-safari-view",
|
||||
"$(SRCROOT)/../node_modules/react-native-linear-gradient/BVLinearGradient",
|
||||
);
|
||||
INFOPLIST_FILE = devhubTests/Info.plist;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
|
||||
@@ -1319,6 +1367,7 @@
|
||||
"$(inherited)",
|
||||
"\"$(SRCROOT)/$(TARGET_NAME)\"",
|
||||
"\"$(SRCROOT)/$(TARGET_NAME)\"",
|
||||
"\"$(SRCROOT)/$(TARGET_NAME)\"",
|
||||
);
|
||||
OTHER_LDFLAGS = (
|
||||
"-ObjC",
|
||||
@@ -1340,6 +1389,7 @@
|
||||
"$(SRCROOT)/../node_modules/react-native-gesture-handler/ios/**",
|
||||
"$(SRCROOT)/../node_modules/react-native-navigation/ios/**",
|
||||
"$(SRCROOT)/../node_modules/react-native-safari-view",
|
||||
"$(SRCROOT)/../node_modules/react-native-linear-gradient/BVLinearGradient",
|
||||
);
|
||||
INFOPLIST_FILE = devhubTests/Info.plist;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
|
||||
@@ -1348,6 +1398,7 @@
|
||||
"$(inherited)",
|
||||
"\"$(SRCROOT)/$(TARGET_NAME)\"",
|
||||
"\"$(SRCROOT)/$(TARGET_NAME)\"",
|
||||
"\"$(SRCROOT)/$(TARGET_NAME)\"",
|
||||
);
|
||||
OTHER_LDFLAGS = (
|
||||
"-ObjC",
|
||||
@@ -1371,6 +1422,7 @@
|
||||
"$(SRCROOT)/../node_modules/react-native-gesture-handler/ios/**",
|
||||
"$(SRCROOT)/../node_modules/react-native-navigation/ios/**",
|
||||
"$(SRCROOT)/../node_modules/react-native-safari-view",
|
||||
"$(SRCROOT)/../node_modules/react-native-linear-gradient/BVLinearGradient",
|
||||
);
|
||||
INFOPLIST_FILE = devhub/Info.plist;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
||||
@@ -1396,6 +1448,7 @@
|
||||
"$(SRCROOT)/../node_modules/react-native-gesture-handler/ios/**",
|
||||
"$(SRCROOT)/../node_modules/react-native-navigation/ios/**",
|
||||
"$(SRCROOT)/../node_modules/react-native-safari-view",
|
||||
"$(SRCROOT)/../node_modules/react-native-linear-gradient/BVLinearGradient",
|
||||
);
|
||||
INFOPLIST_FILE = devhub/Info.plist;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
||||
@@ -1427,6 +1480,7 @@
|
||||
"$(SRCROOT)/../node_modules/react-native-gesture-handler/ios/**",
|
||||
"$(SRCROOT)/../node_modules/react-native-navigation/ios/**",
|
||||
"$(SRCROOT)/../node_modules/react-native-safari-view",
|
||||
"$(SRCROOT)/../node_modules/react-native-linear-gradient/BVLinearGradient",
|
||||
);
|
||||
INFOPLIST_FILE = "devhub-tvOS/Info.plist";
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
||||
@@ -1434,6 +1488,7 @@
|
||||
"$(inherited)",
|
||||
"\"$(SRCROOT)/$(TARGET_NAME)\"",
|
||||
"\"$(SRCROOT)/$(TARGET_NAME)\"",
|
||||
"\"$(SRCROOT)/$(TARGET_NAME)\"",
|
||||
);
|
||||
OTHER_LDFLAGS = (
|
||||
"-ObjC",
|
||||
@@ -1465,6 +1520,7 @@
|
||||
"$(SRCROOT)/../node_modules/react-native-gesture-handler/ios/**",
|
||||
"$(SRCROOT)/../node_modules/react-native-navigation/ios/**",
|
||||
"$(SRCROOT)/../node_modules/react-native-safari-view",
|
||||
"$(SRCROOT)/../node_modules/react-native-linear-gradient/BVLinearGradient",
|
||||
);
|
||||
INFOPLIST_FILE = "devhub-tvOS/Info.plist";
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
||||
@@ -1472,6 +1528,7 @@
|
||||
"$(inherited)",
|
||||
"\"$(SRCROOT)/$(TARGET_NAME)\"",
|
||||
"\"$(SRCROOT)/$(TARGET_NAME)\"",
|
||||
"\"$(SRCROOT)/$(TARGET_NAME)\"",
|
||||
);
|
||||
OTHER_LDFLAGS = (
|
||||
"-ObjC",
|
||||
@@ -1502,6 +1559,7 @@
|
||||
"$(inherited)",
|
||||
"\"$(SRCROOT)/$(TARGET_NAME)\"",
|
||||
"\"$(SRCROOT)/$(TARGET_NAME)\"",
|
||||
"\"$(SRCROOT)/$(TARGET_NAME)\"",
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "com.facebook.REACT.devhub-tvOSTests";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
@@ -1528,6 +1586,7 @@
|
||||
"$(inherited)",
|
||||
"\"$(SRCROOT)/$(TARGET_NAME)\"",
|
||||
"\"$(SRCROOT)/$(TARGET_NAME)\"",
|
||||
"\"$(SRCROOT)/$(TARGET_NAME)\"",
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "com.facebook.REACT.devhub-tvOSTests";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
"react": "^16.2.0",
|
||||
"react-native": "^0.51.0",
|
||||
"react-native-gesture-handler": "^1.0.0-alpha.37",
|
||||
"react-native-linear-gradient": "^2.4.0",
|
||||
"react-native-navigation": "^1.1.334",
|
||||
"react-native-safari-view": "^2.1.0",
|
||||
"react-native-vector-icons": "^4.4.3",
|
||||
@@ -50,7 +51,9 @@
|
||||
},
|
||||
"jest": {
|
||||
"preset": "react-native",
|
||||
"setupFiles": ["./jest/setup.js"],
|
||||
"setupFiles": [
|
||||
"./jest/setup.js"
|
||||
],
|
||||
"globals": {
|
||||
"ts-jest": {
|
||||
"useBabelrc": true
|
||||
|
||||
@@ -3,14 +3,41 @@ import { StyleSheet, View, ViewStyle } from 'react-native'
|
||||
|
||||
import theme from '../../styles/themes/dark'
|
||||
import { contentPadding } from '../../styles/variables'
|
||||
import { IGitHubEvent } from '../../types/index'
|
||||
import {
|
||||
IForkEvent,
|
||||
IGitHubCommit,
|
||||
IGitHubCommitCommentEvent,
|
||||
IGitHubEvent,
|
||||
IGitHubPage,
|
||||
IGitHubRepo,
|
||||
IGitHubUser,
|
||||
IGollumEvent,
|
||||
IIssuesEvent,
|
||||
IMemberEvent,
|
||||
IPullRequestEvent,
|
||||
IPushEvent,
|
||||
IReleaseEvent,
|
||||
} from '../../types/index'
|
||||
import {
|
||||
getEventIconAndColor,
|
||||
getEventText,
|
||||
} from '../../utils/helpers/github/events'
|
||||
import { getOwnerAndRepo } from '../../utils/helpers/github/shared'
|
||||
import {
|
||||
getIssueIconAndColor,
|
||||
getOwnerAndRepo,
|
||||
getPullRequestIconAndColor,
|
||||
} from '../../utils/helpers/github/shared'
|
||||
import { getRepoFullNameFromObject } from '../../utils/helpers/github/url'
|
||||
import EventCardHeader from './partials/EventCardHeader'
|
||||
import BranchRow from './partials/rows/BranchRow'
|
||||
import CommentRow from './partials/rows/CommentRow'
|
||||
import CommitListRow from './partials/rows/CommitListRow'
|
||||
import IssueOrPullRequestRow from './partials/rows/IssueOrPullRequestRow'
|
||||
import ReleaseRow from './partials/rows/ReleaseRow'
|
||||
import RepositoryListRow from './partials/rows/RepositoryListRow'
|
||||
import RepositoryRow from './partials/rows/RepositoryRow'
|
||||
import UserListRow from './partials/rows/UserListRow'
|
||||
import WikiPageListRow from './partials/rows/WikiPageListRow'
|
||||
|
||||
export interface IProps {
|
||||
event: IGitHubEvent
|
||||
@@ -29,9 +56,44 @@ const styles = StyleSheet.create({
|
||||
export default class EventCard extends PureComponent<IProps> {
|
||||
render() {
|
||||
const { event } = this.props
|
||||
const { actor, payload, repo: _repo, type } = event
|
||||
|
||||
const repoFullName = event.repo.full_name || event.repo.name || ''
|
||||
const { owner: orgName, repo: repoName } = getOwnerAndRepo(repoFullName)
|
||||
const { comment } = payload as IGitHubCommitCommentEvent['payload']
|
||||
const { commits: _commits } = payload as IPushEvent['payload']
|
||||
const { forkee } = payload as IForkEvent['payload']
|
||||
const { member: _member } = payload as IMemberEvent['payload']
|
||||
const { release } = payload as IReleaseEvent['payload']
|
||||
const { pages: _pages } = payload as IGollumEvent['payload']
|
||||
const {
|
||||
pull_request: pullRequest,
|
||||
} = payload as IPullRequestEvent['payload']
|
||||
const { issue } = payload as IIssuesEvent['payload']
|
||||
const { ref: branchName } = payload as IPushEvent['payload']
|
||||
|
||||
const isRead = false // TODO
|
||||
const commits: IGitHubCommit[] = (_commits || []).filter(Boolean)
|
||||
const repos: IGitHubRepo[] = [_repo].filter(Boolean) // TODO
|
||||
const users: IGitHubUser[] = [_member].filter(Boolean) // TODO
|
||||
const pages: IGitHubPage[] = (_pages || []).filter(Boolean)
|
||||
|
||||
const repo = repos.length === 1 ? repos[0] : undefined
|
||||
|
||||
const commitIds = commits
|
||||
.filter(Boolean)
|
||||
.map((item: IGitHubCommit) => item.sha)
|
||||
const pageIds = pages.filter(Boolean).map((item: IGitHubPage) => item.sha)
|
||||
const repoIds = repos.filter(Boolean).map((item: IGitHubRepo) => item.id)
|
||||
const userIds = users.filter(Boolean).map((item: IGitHubUser) => item.id)
|
||||
|
||||
const repoFullName = repo && getRepoFullNameFromObject(repo)
|
||||
const { owner: repoOwnerName, repo: repoName } = getOwnerAndRepo(
|
||||
repoFullName || '',
|
||||
)
|
||||
|
||||
const forkRepoFullName = getRepoFullNameFromObject(forkee)
|
||||
const { owner: forkRepoOwnerName, repo: forkRepoName } = getOwnerAndRepo(
|
||||
forkRepoFullName,
|
||||
)
|
||||
|
||||
const cardIconDetails = getEventIconAndColor(event, theme)
|
||||
const cardIconName = cardIconDetails.subIcon || cardIconDetails.icon
|
||||
@@ -39,6 +101,32 @@ export default class EventCard extends PureComponent<IProps> {
|
||||
|
||||
const actionText = getEventText(event)
|
||||
|
||||
const isPush = type === 'PushEvent'
|
||||
const isForcePush = isPush && (payload as IPushEvent).forced
|
||||
|
||||
const {
|
||||
icon: pullRequestIconName,
|
||||
color: pullRequestIconColor,
|
||||
} = pullRequest
|
||||
? getPullRequestIconAndColor(pullRequest)
|
||||
: { icon: undefined, color: undefined }
|
||||
|
||||
const pullRequestURL =
|
||||
pullRequest &&
|
||||
(comment && !comment.body && comment.html_url
|
||||
? comment.html_url || comment.url
|
||||
: pullRequest.html_url || pullRequest.url)
|
||||
|
||||
const { icon: issueIconName, color: issueIconColor } = issue
|
||||
? getIssueIconAndColor(issue)
|
||||
: { icon: undefined, color: undefined }
|
||||
|
||||
const issueURL =
|
||||
issue &&
|
||||
(comment && !comment.body && (comment.html_url || comment.url)
|
||||
? comment.html_url || comment.url
|
||||
: issue.html_url || issue.url)
|
||||
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<EventCardHeader
|
||||
@@ -47,10 +135,147 @@ export default class EventCard extends PureComponent<IProps> {
|
||||
cardIconName={cardIconName}
|
||||
username={event.actor.login}
|
||||
/>
|
||||
{Boolean(event.repo && orgName && repoName) && (
|
||||
|
||||
{repos.length > 0 && (
|
||||
<RepositoryListRow
|
||||
key={`repo-list-row-${repoIds.join('-')}`}
|
||||
isForcePush={isForcePush}
|
||||
isPush={isPush}
|
||||
isRead={isRead}
|
||||
repos={repos}
|
||||
theme={theme}
|
||||
/>
|
||||
)}
|
||||
|
||||
{Boolean(repo && repoOwnerName && repoName && branchName) && (
|
||||
<BranchRow
|
||||
key={`branch-row-${branchName}`}
|
||||
branch={branchName}
|
||||
isRead={isRead}
|
||||
ownerName={repoOwnerName!}
|
||||
repositoryName={repoName!}
|
||||
type={type}
|
||||
/>
|
||||
)}
|
||||
|
||||
{Boolean(forkee && forkRepoOwnerName && forkRepoName) && (
|
||||
<RepositoryRow
|
||||
owner={orgName as string}
|
||||
repository={repoName as string}
|
||||
key={`fork-row-${forkee.id}`}
|
||||
isForcePush={isForcePush}
|
||||
isFork
|
||||
isRead={isRead}
|
||||
ownerName={forkRepoOwnerName!}
|
||||
repositoryName={forkRepoName!}
|
||||
/>
|
||||
)}
|
||||
|
||||
{users.length > 0 && (
|
||||
<UserListRow
|
||||
key={`user-list-row-${userIds.join('-')}`}
|
||||
isRead={isRead}
|
||||
users={users}
|
||||
theme={theme}
|
||||
/>
|
||||
)}
|
||||
|
||||
{pages.length > 0 && (
|
||||
<WikiPageListRow
|
||||
key={`wiki-page-list-row-${pageIds.join('-')}`}
|
||||
isRead={isRead}
|
||||
pages={pages}
|
||||
theme={theme}
|
||||
/>
|
||||
)}
|
||||
|
||||
{Boolean(pullRequest) && (
|
||||
<IssueOrPullRequestRow
|
||||
key={`pr-row-${pullRequest.id}`}
|
||||
iconColor={pullRequestIconColor!}
|
||||
iconName={pullRequestIconName!}
|
||||
isRead={isRead}
|
||||
issueNumber={pullRequest.number}
|
||||
theme={theme}
|
||||
title={pullRequest.title}
|
||||
url={pullRequestURL}
|
||||
username={pullRequest.user.login}
|
||||
/>
|
||||
)}
|
||||
|
||||
{commits.length > 0 && (
|
||||
<CommitListRow
|
||||
key={`commit-list-row-${commitIds.join('-')}`}
|
||||
commits={commits}
|
||||
isRead={isRead}
|
||||
theme={theme}
|
||||
/>
|
||||
)}
|
||||
|
||||
{Boolean(issue) && (
|
||||
<IssueOrPullRequestRow
|
||||
key={`issue-row-${issue.id}`}
|
||||
iconColor={issueIconColor!}
|
||||
iconName={issueIconName!}
|
||||
isRead={isRead}
|
||||
issueNumber={issue.number}
|
||||
theme={theme}
|
||||
title={issue.title}
|
||||
url={issueURL}
|
||||
username={issue.user.login}
|
||||
/>
|
||||
)}
|
||||
|
||||
{(type === 'IssuesEvent' &&
|
||||
(payload as IIssuesEvent['payload']).action === 'opened' &&
|
||||
Boolean((payload as IIssuesEvent['payload']).issue.body) && (
|
||||
<CommentRow
|
||||
key={`issue-body-row-${
|
||||
(payload as IIssuesEvent['payload']).issue.id
|
||||
}`}
|
||||
body={(payload as IIssuesEvent['payload']).issue.body}
|
||||
isRead={isRead}
|
||||
type={type}
|
||||
url={
|
||||
(payload as IIssuesEvent['payload']).issue.html_url ||
|
||||
(payload as IIssuesEvent['payload']).issue.url
|
||||
}
|
||||
username={actor.login}
|
||||
/>
|
||||
)) ||
|
||||
(type === 'PullRequestEvent' &&
|
||||
(payload as IPullRequestEvent['payload']).action === 'opened' &&
|
||||
Boolean(pullRequest.body) && (
|
||||
<CommentRow
|
||||
key={`pr-body-row-${pullRequest.id}`}
|
||||
body={pullRequest.body}
|
||||
isRead={isRead}
|
||||
url={pullRequest.html_url || pullRequest.url}
|
||||
username={actor.login}
|
||||
type={type}
|
||||
/>
|
||||
)) ||
|
||||
(Boolean(comment && comment.body) && (
|
||||
<CommentRow
|
||||
key={`comment-row-${comment.id}`}
|
||||
body={comment.body}
|
||||
isRead={isRead}
|
||||
type={type}
|
||||
url={comment.html_url || comment.url}
|
||||
username={actor.login}
|
||||
/>
|
||||
))}
|
||||
|
||||
{Boolean(release) && (
|
||||
<ReleaseRow
|
||||
key={`release-row-${release.id}`}
|
||||
body={release.body}
|
||||
branch={release.target_commitish}
|
||||
isRead={isRead}
|
||||
name={release.name}
|
||||
ownerName={repoOwnerName!}
|
||||
repositoryName={repoName!}
|
||||
tagName={release.tag_name}
|
||||
type={type}
|
||||
url={release.html_url || release.url}
|
||||
/>
|
||||
)}
|
||||
</View>
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
import React from 'react'
|
||||
import { FlatList } from 'react-native'
|
||||
|
||||
import theme from '../../styles/themes/dark'
|
||||
import { contentPadding } from '../../styles/variables'
|
||||
import { IGitHubEvent } from '../../types'
|
||||
import TransparentTextOverlay from '../common/TransparentTextOverlay'
|
||||
import CardItemSeparator from './partials/CardItemSeparator'
|
||||
import SwipeableEventCard from './SwipeableEventCard'
|
||||
|
||||
@@ -11,7 +14,7 @@ export interface IProps {
|
||||
|
||||
class EventCards extends React.PureComponent<IProps> {
|
||||
keyExtractor(event: IGitHubEvent) {
|
||||
return event.id
|
||||
return `${event.id}`
|
||||
}
|
||||
|
||||
renderItem({ item: event }: { item: IGitHubEvent }) {
|
||||
@@ -22,12 +25,18 @@ class EventCards extends React.PureComponent<IProps> {
|
||||
const { events } = this.props
|
||||
|
||||
return (
|
||||
<FlatList
|
||||
data={events}
|
||||
ItemSeparatorComponent={CardItemSeparator}
|
||||
keyExtractor={this.keyExtractor}
|
||||
renderItem={this.renderItem}
|
||||
/>
|
||||
<TransparentTextOverlay
|
||||
color={theme.base02}
|
||||
size={contentPadding}
|
||||
from="vertical"
|
||||
>
|
||||
<FlatList
|
||||
data={events}
|
||||
ItemSeparatorComponent={CardItemSeparator}
|
||||
keyExtractor={this.keyExtractor}
|
||||
renderItem={this.renderItem}
|
||||
/>
|
||||
</TransparentTextOverlay>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,7 +32,9 @@ export default class NotificationCard extends PureComponent<IProps> {
|
||||
|
||||
const repoFullName =
|
||||
notification.repository.full_name || notification.repository.name || ''
|
||||
const { owner: orgName, repo: repoName } = getOwnerAndRepo(repoFullName)
|
||||
const { owner: repoOwnerName, repo: repoName } = getOwnerAndRepo(
|
||||
repoFullName,
|
||||
)
|
||||
|
||||
const cardIconDetails = getNotificationIconAndColor(
|
||||
notification,
|
||||
@@ -54,10 +56,10 @@ export default class NotificationCard extends PureComponent<IProps> {
|
||||
labelColor={labelColor}
|
||||
labelText={labelText}
|
||||
/>
|
||||
{Boolean(orgName && repoName) && (
|
||||
{Boolean(repoOwnerName && repoName) && (
|
||||
<RepositoryRow
|
||||
owner={orgName as string}
|
||||
repository={repoName as string}
|
||||
ownerName={repoOwnerName as string}
|
||||
repositoryName={repoName as string}
|
||||
/>
|
||||
)}
|
||||
</View>
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
import React from 'react'
|
||||
import { FlatList } from 'react-native'
|
||||
|
||||
import theme from '../../styles/themes/dark'
|
||||
import { contentPadding } from '../../styles/variables'
|
||||
import { IGitHubNotification } from '../../types'
|
||||
import TransparentTextOverlay from '../common/TransparentTextOverlay'
|
||||
import NotificationCard from './NotificationCard'
|
||||
import CardItemSeparator from './partials/CardItemSeparator'
|
||||
|
||||
@@ -11,7 +14,7 @@ export interface IProps {
|
||||
|
||||
class NotificationCards extends React.PureComponent<IProps> {
|
||||
keyExtractor(notification: IGitHubNotification) {
|
||||
return notification.id
|
||||
return `${notification.id}`
|
||||
}
|
||||
|
||||
renderItem({ item: notification }: { item: IGitHubNotification }) {
|
||||
@@ -26,12 +29,19 @@ class NotificationCards extends React.PureComponent<IProps> {
|
||||
render() {
|
||||
const { notifications } = this.props
|
||||
return (
|
||||
<FlatList
|
||||
data={notifications}
|
||||
ItemSeparatorComponent={CardItemSeparator}
|
||||
keyExtractor={this.keyExtractor}
|
||||
renderItem={this.renderItem}
|
||||
/>
|
||||
<TransparentTextOverlay
|
||||
color={theme.base02}
|
||||
size={contentPadding}
|
||||
from="vertical"
|
||||
>
|
||||
<FlatList
|
||||
key="notification-cards-flat-list"
|
||||
data={notifications}
|
||||
ItemSeparatorComponent={CardItemSeparator}
|
||||
keyExtractor={this.keyExtractor}
|
||||
renderItem={this.renderItem}
|
||||
/>
|
||||
</TransparentTextOverlay>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,8 +21,8 @@ export default class SwipeableEventCard extends PureComponent<IProps> {
|
||||
leftActions={[
|
||||
{
|
||||
color: theme.blue,
|
||||
icon: 'read',
|
||||
key: 'read',
|
||||
icon: 'isRead',
|
||||
key: 'isRead',
|
||||
label: 'Read',
|
||||
onPress: this.onMarkAsRead,
|
||||
type: 'FULL',
|
||||
|
||||
83
src/components/cards/partials/CardItemId.tsx
Normal file
83
src/components/cards/partials/CardItemId.tsx
Normal file
@@ -0,0 +1,83 @@
|
||||
import React, { SFC } from 'react'
|
||||
import {
|
||||
StyleSheet,
|
||||
Text,
|
||||
TextStyle,
|
||||
TouchableOpacity,
|
||||
ViewStyle,
|
||||
} from 'react-native'
|
||||
import Icon from 'react-native-vector-icons/Octicons'
|
||||
|
||||
import { radius } from '../../../styles/variables'
|
||||
import { IGitHubIcon, ITheme } from '../../../types'
|
||||
import cardStyles from '../styles'
|
||||
import { getGithubURLPressHandler } from './rows/helpers'
|
||||
|
||||
export interface IProps {
|
||||
icon?: IGitHubIcon
|
||||
id: number | string
|
||||
isRead?: boolean
|
||||
style?: ViewStyle
|
||||
theme: ITheme
|
||||
url: string
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
alignItems: 'center',
|
||||
borderRadius: radius,
|
||||
borderWidth: StyleSheet.hairlineWidth,
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'space-between',
|
||||
paddingHorizontal: 4,
|
||||
} as ViewStyle,
|
||||
|
||||
text: {
|
||||
backgroundColor: 'transparent',
|
||||
fontSize: 12,
|
||||
fontWeight: 'bold',
|
||||
lineHeight: 20,
|
||||
opacity: 0.9,
|
||||
} as TextStyle,
|
||||
})
|
||||
|
||||
export const CardItemId: SFC<IProps> = ({
|
||||
icon,
|
||||
id,
|
||||
isRead,
|
||||
style,
|
||||
theme,
|
||||
url,
|
||||
}) => {
|
||||
if (!id && !icon) return null
|
||||
|
||||
const parsedNumber = parseInt(`${id}`, 10) || id
|
||||
|
||||
return (
|
||||
<TouchableOpacity
|
||||
onPress={url ? getGithubURLPressHandler(url) : undefined}
|
||||
style={[
|
||||
styles.container,
|
||||
{
|
||||
backgroundColor: theme.base03,
|
||||
borderColor: theme.base03,
|
||||
},
|
||||
style,
|
||||
]}
|
||||
>
|
||||
<Text
|
||||
style={[
|
||||
styles.text,
|
||||
{ color: isRead ? theme.base05 : theme.base04 },
|
||||
isRead && cardStyles.mutedText,
|
||||
isRead && { fontWeight: 'normal' },
|
||||
]}
|
||||
>
|
||||
{icon ? <Icon name={icon} /> : ''}
|
||||
{parsedNumber && icon ? ' ' : ''}
|
||||
{typeof parsedNumber === 'number' ? '#' : ''}
|
||||
{parsedNumber}
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
)
|
||||
}
|
||||
66
src/components/cards/partials/rows/BranchRow.tsx
Normal file
66
src/components/cards/partials/rows/BranchRow.tsx
Normal file
@@ -0,0 +1,66 @@
|
||||
import React, { SFC } from 'react'
|
||||
import { Text, TouchableOpacity, View } from 'react-native'
|
||||
import Icon from 'react-native-vector-icons/Octicons'
|
||||
|
||||
import { IGitHubEventType } from '../../../../types'
|
||||
import Avatar from '../../../common/Avatar'
|
||||
import cardStyles from '../../styles'
|
||||
import { getBranchPressHandler } from './helpers'
|
||||
import rowStyles from './styles'
|
||||
|
||||
export interface IProps {
|
||||
branch: string
|
||||
isRead?: boolean
|
||||
ownerName: string
|
||||
repositoryName: string
|
||||
type: IGitHubEventType
|
||||
}
|
||||
|
||||
export interface IState {}
|
||||
|
||||
const BranchRow: SFC<IProps> = ({
|
||||
branch: _branch,
|
||||
isRead,
|
||||
ownerName,
|
||||
repositoryName,
|
||||
type,
|
||||
}) => {
|
||||
const branch = (_branch || '').replace('refs/heads/', '')
|
||||
if (!branch) return null
|
||||
|
||||
const isBranchMainEventAction =
|
||||
type === 'CreateEvent' || type === 'DeleteEvent'
|
||||
if (branch === 'master' && !isBranchMainEventAction) return null
|
||||
|
||||
return (
|
||||
<View style={rowStyles.container}>
|
||||
<View style={cardStyles.leftColumn}>
|
||||
<Avatar username={ownerName} small style={cardStyles.avatar} />
|
||||
</View>
|
||||
|
||||
<View style={cardStyles.rightColumn}>
|
||||
<TouchableOpacity
|
||||
onPress={getBranchPressHandler(ownerName, repositoryName, branch)}
|
||||
style={rowStyles.mainContentContainer}
|
||||
>
|
||||
<Text
|
||||
style={[
|
||||
cardStyles.normalText,
|
||||
(isRead || !isBranchMainEventAction) && cardStyles.mutedText,
|
||||
]}
|
||||
>
|
||||
<Text
|
||||
numberOfLines={1}
|
||||
style={isRead ? cardStyles.mutedText : cardStyles.normalText}
|
||||
>
|
||||
<Icon name="git-branch" />{' '}
|
||||
</Text>
|
||||
{branch}
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
</View>
|
||||
)
|
||||
}
|
||||
|
||||
export default BranchRow
|
||||
55
src/components/cards/partials/rows/CommentRow.tsx
Normal file
55
src/components/cards/partials/rows/CommentRow.tsx
Normal file
@@ -0,0 +1,55 @@
|
||||
import React, { SFC } from 'react'
|
||||
import { Text, TouchableOpacity, View } from 'react-native'
|
||||
|
||||
import { IGitHubEventType } from '../../../../types'
|
||||
import { trimNewLinesAndSpaces } from '../../../../utils/helpers/shared'
|
||||
import Avatar from '../../../common/Avatar'
|
||||
import cardStyles from '../../styles'
|
||||
import { getGithubURLPressHandler } from './helpers'
|
||||
import rowStyles from './styles'
|
||||
|
||||
export interface IProps {
|
||||
body: string
|
||||
isRead?: boolean
|
||||
numberOfLines?: number
|
||||
username: string
|
||||
type: IGitHubEventType
|
||||
url?: string
|
||||
}
|
||||
|
||||
export interface IState {}
|
||||
|
||||
const CommentRow: SFC<IProps> = ({
|
||||
body: _body,
|
||||
isRead,
|
||||
numberOfLines = 4,
|
||||
url,
|
||||
username,
|
||||
}) => {
|
||||
const body = trimNewLinesAndSpaces(_body, 400)
|
||||
if (!body) return null
|
||||
|
||||
return (
|
||||
<View style={rowStyles.container}>
|
||||
<View style={[cardStyles.leftColumn, cardStyles.leftColumnAlignTop]}>
|
||||
<Avatar username={username} small style={cardStyles.avatar} />
|
||||
</View>
|
||||
|
||||
<View style={cardStyles.rightColumn}>
|
||||
<TouchableOpacity
|
||||
onPress={getGithubURLPressHandler(url)}
|
||||
style={rowStyles.mainContentContainer}
|
||||
>
|
||||
<Text
|
||||
numberOfLines={numberOfLines}
|
||||
style={[cardStyles.normalText, isRead && cardStyles.mutedText]}
|
||||
>
|
||||
{body}
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
</View>
|
||||
)
|
||||
}
|
||||
|
||||
export default CommentRow
|
||||
38
src/components/cards/partials/rows/CommitListRow.tsx
Normal file
38
src/components/cards/partials/rows/CommitListRow.tsx
Normal file
@@ -0,0 +1,38 @@
|
||||
import React from 'react'
|
||||
|
||||
import CommitRow from './CommitRow'
|
||||
import RowList from './RowList'
|
||||
|
||||
import { IGitHubCommit, ITheme } from '../../../../types'
|
||||
|
||||
export interface IProps {
|
||||
isRead?: boolean
|
||||
maxHeight?: number
|
||||
commits: IGitHubCommit[]
|
||||
theme: ITheme
|
||||
}
|
||||
|
||||
export default class CommitListRow extends React.PureComponent<IProps> {
|
||||
renderItem({ item: commit }: { item: IGitHubCommit }) {
|
||||
if (!(commit && commit.sha && commit.message)) return null
|
||||
|
||||
return (
|
||||
<CommitRow
|
||||
key={`commit-row-${commit.sha}`}
|
||||
{...this.props}
|
||||
authorEmail={commit.author.email}
|
||||
authorName={commit.author.name}
|
||||
message={commit.message}
|
||||
url={commit.url}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
render() {
|
||||
const { commits, ...props } = this.props
|
||||
|
||||
if (!(commits && commits.length > 0)) return null
|
||||
|
||||
return <RowList {...props} data={commits} renderItem={this.renderItem} />
|
||||
}
|
||||
}
|
||||
91
src/components/cards/partials/rows/CommitRow.tsx
Normal file
91
src/components/cards/partials/rows/CommitRow.tsx
Normal file
@@ -0,0 +1,91 @@
|
||||
import React, { SFC } from 'react'
|
||||
import { Text, TouchableOpacity, View } from 'react-native'
|
||||
import Icon from 'react-native-vector-icons/Octicons'
|
||||
|
||||
import { tryGetUsernameFromGitHubEmail } from '../../../../utils/helpers/github/shared'
|
||||
import {
|
||||
getGitHubSearchURL,
|
||||
getGitHubURLForUser,
|
||||
} from '../../../../utils/helpers/github/url'
|
||||
import { trimNewLinesAndSpaces } from '../../../../utils/helpers/shared'
|
||||
import Avatar from '../../../common/Avatar'
|
||||
import cardStyles from '../../styles'
|
||||
import { getGithubURLPressHandler } from './helpers'
|
||||
import rowStyles from './styles'
|
||||
|
||||
export interface IProps {
|
||||
authorEmail?: string
|
||||
authorName?: string
|
||||
authorUsername?: string
|
||||
isRead?: boolean
|
||||
message: string
|
||||
url: string
|
||||
}
|
||||
|
||||
export interface IState {}
|
||||
|
||||
const CommitRow: SFC<IProps> = ({
|
||||
authorEmail,
|
||||
authorName,
|
||||
authorUsername: _authorUsername,
|
||||
isRead,
|
||||
message: _message,
|
||||
url,
|
||||
}) => {
|
||||
const message = trimNewLinesAndSpaces(_message)
|
||||
if (!message) return null
|
||||
|
||||
const authorUsername =
|
||||
_authorUsername || tryGetUsernameFromGitHubEmail(authorEmail)
|
||||
|
||||
let byText = authorName
|
||||
if (authorUsername) byText += ` @${authorUsername}`
|
||||
else if (authorEmail)
|
||||
byText += byText ? ` <${authorEmail}>` : ` ${authorEmail}`
|
||||
byText = trimNewLinesAndSpaces(byText)
|
||||
|
||||
return (
|
||||
<View style={rowStyles.container}>
|
||||
<View style={cardStyles.leftColumn}>
|
||||
<Avatar
|
||||
email={authorEmail}
|
||||
username={authorUsername}
|
||||
small
|
||||
style={cardStyles.avatar}
|
||||
linkURL={
|
||||
authorUsername
|
||||
? getGitHubURLForUser(authorUsername)
|
||||
: getGitHubSearchURL({ q: authorEmail || '', type: 'Users' })
|
||||
}
|
||||
/>
|
||||
</View>
|
||||
|
||||
<View style={cardStyles.rightColumn}>
|
||||
<TouchableOpacity
|
||||
onPress={getGithubURLPressHandler(url)}
|
||||
style={rowStyles.mainContentContainer}
|
||||
>
|
||||
<Text
|
||||
numberOfLines={1}
|
||||
style={[cardStyles.normalText, isRead && cardStyles.mutedText]}
|
||||
>
|
||||
<Icon name="git-commit" /> {message}
|
||||
{Boolean(byText) && (
|
||||
<Text
|
||||
style={[
|
||||
cardStyles.normalText,
|
||||
cardStyles.smallText,
|
||||
cardStyles.mutedText,
|
||||
]}
|
||||
>
|
||||
{` by ${byText}`}
|
||||
</Text>
|
||||
)}
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
</View>
|
||||
)
|
||||
}
|
||||
|
||||
export default CommitRow
|
||||
99
src/components/cards/partials/rows/IssueOrPullRequestRow.tsx
Normal file
99
src/components/cards/partials/rows/IssueOrPullRequestRow.tsx
Normal file
@@ -0,0 +1,99 @@
|
||||
import React, { SFC } from 'react'
|
||||
import {
|
||||
StyleSheet,
|
||||
Text,
|
||||
TouchableOpacity,
|
||||
View,
|
||||
ViewStyle,
|
||||
} from 'react-native'
|
||||
import Icon from 'react-native-vector-icons/Octicons'
|
||||
|
||||
import defaultStyles from '../../../../styles/styles'
|
||||
import { contentPadding } from '../../../../styles/variables'
|
||||
import { ITheme } from '../../../../types'
|
||||
import { trimNewLinesAndSpaces } from '../../../../utils/helpers/shared'
|
||||
import Avatar from '../../../common/Avatar'
|
||||
import cardStyles from '../../styles'
|
||||
import { CardItemId } from '../CardItemId'
|
||||
import { getGithubURLPressHandler } from './helpers'
|
||||
import rowStyles from './styles'
|
||||
|
||||
export interface IProps {
|
||||
iconColor?: string
|
||||
iconName: string
|
||||
isRead?: boolean
|
||||
issueNumber: number
|
||||
theme: ITheme
|
||||
title: string
|
||||
url: string
|
||||
username: string
|
||||
}
|
||||
|
||||
export interface IState {}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
cardItemId: {
|
||||
marginLeft: contentPadding,
|
||||
} as ViewStyle,
|
||||
})
|
||||
|
||||
const IssueOrPullRequestRow: SFC<IProps> = ({
|
||||
iconColor,
|
||||
iconName,
|
||||
isRead,
|
||||
issueNumber,
|
||||
theme,
|
||||
title: _title,
|
||||
url,
|
||||
username,
|
||||
}) => {
|
||||
const title = trimNewLinesAndSpaces(_title)
|
||||
if (!title) return null
|
||||
|
||||
const byText = username ? `@${username}` : ''
|
||||
|
||||
return (
|
||||
<View style={rowStyles.container}>
|
||||
<View style={cardStyles.leftColumn}>
|
||||
<Avatar username={username} small style={cardStyles.avatar} />
|
||||
</View>
|
||||
|
||||
<View style={cardStyles.rightColumn}>
|
||||
<TouchableOpacity
|
||||
onPress={getGithubURLPressHandler(url)}
|
||||
style={rowStyles.mainContentContainer}
|
||||
>
|
||||
<Text numberOfLines={1} style={defaultStyles.full}>
|
||||
<Text
|
||||
style={[cardStyles.normalText, isRead && cardStyles.mutedText]}
|
||||
>
|
||||
<Icon color={iconColor} name={iconName} /> {title}
|
||||
{Boolean(byText) && (
|
||||
<Text
|
||||
style={[
|
||||
cardStyles.normalText,
|
||||
cardStyles.smallText,
|
||||
cardStyles.mutedText,
|
||||
]}
|
||||
>
|
||||
{' '}
|
||||
by {byText}
|
||||
</Text>
|
||||
)}
|
||||
</Text>
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
|
||||
<CardItemId
|
||||
id={issueNumber}
|
||||
isRead={isRead}
|
||||
style={styles.cardItemId}
|
||||
theme={theme}
|
||||
url={url}
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
)
|
||||
}
|
||||
|
||||
export default IssueOrPullRequestRow
|
||||
112
src/components/cards/partials/rows/ReleaseRow.tsx
Normal file
112
src/components/cards/partials/rows/ReleaseRow.tsx
Normal file
@@ -0,0 +1,112 @@
|
||||
import React, { SFC } from 'react'
|
||||
import { Text, TouchableOpacity, View } from 'react-native'
|
||||
import Icon from 'react-native-vector-icons/Octicons'
|
||||
|
||||
import { IGitHubEventType } from '../../../../types'
|
||||
import { getOwnerAndRepo } from '../../../../utils/helpers/github/shared'
|
||||
import { getRepoFullNameFromUrl } from '../../../../utils/helpers/github/url'
|
||||
import { trimNewLinesAndSpaces } from '../../../../utils/helpers/shared'
|
||||
import Avatar from '../../../common/Avatar'
|
||||
import cardStyles from '../../styles'
|
||||
import BranchRow from './BranchRow'
|
||||
import { getGithubURLPressHandler } from './helpers'
|
||||
import rowStyles from './styles'
|
||||
|
||||
export interface IProps {
|
||||
branch: string
|
||||
body: string
|
||||
isRead?: boolean
|
||||
name: string
|
||||
ownerName: string
|
||||
repositoryName: string
|
||||
tagName: string
|
||||
type: IGitHubEventType
|
||||
url: string
|
||||
}
|
||||
|
||||
export interface IState {}
|
||||
|
||||
const ReleaseRow: SFC<IProps> = ({
|
||||
body: _body,
|
||||
branch,
|
||||
isRead,
|
||||
name: _name,
|
||||
tagName: _tagName,
|
||||
type,
|
||||
url,
|
||||
}) => {
|
||||
const body = trimNewLinesAndSpaces(_body)
|
||||
const name = trimNewLinesAndSpaces(_name)
|
||||
const tagName = trimNewLinesAndSpaces(_tagName)
|
||||
|
||||
const { owner: ownerName, repo: repositoryName } = getOwnerAndRepo(
|
||||
getRepoFullNameFromUrl(url),
|
||||
)
|
||||
|
||||
return (
|
||||
<View>
|
||||
{Boolean(branch && ownerName && repositoryName) && (
|
||||
<BranchRow
|
||||
key={`branch-row-${branch}`}
|
||||
branch={branch}
|
||||
ownerName={ownerName!}
|
||||
repositoryName={repositoryName!}
|
||||
type={type}
|
||||
isRead={isRead}
|
||||
/>
|
||||
)}
|
||||
|
||||
<View style={rowStyles.container}>
|
||||
<View style={cardStyles.leftColumn}>
|
||||
<Avatar username={ownerName} small style={cardStyles.avatar} />
|
||||
</View>
|
||||
|
||||
<View style={cardStyles.rightColumn}>
|
||||
<TouchableOpacity
|
||||
onPress={getGithubURLPressHandler(url)}
|
||||
style={rowStyles.mainContentContainer}
|
||||
>
|
||||
<Text
|
||||
style={[cardStyles.normalText, isRead && cardStyles.mutedText]}
|
||||
>
|
||||
<Text
|
||||
numberOfLines={1}
|
||||
style={isRead ? cardStyles.mutedText : cardStyles.normalText}
|
||||
>
|
||||
<Icon name="tag" />{' '}
|
||||
</Text>
|
||||
{name || tagName}
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
<View style={rowStyles.container}>
|
||||
<View style={cardStyles.leftColumn}>
|
||||
<Avatar username={ownerName} small style={cardStyles.avatar} />
|
||||
</View>
|
||||
|
||||
<View style={cardStyles.rightColumn}>
|
||||
<TouchableOpacity
|
||||
onPress={getGithubURLPressHandler(url)}
|
||||
style={rowStyles.mainContentContainer}
|
||||
>
|
||||
<Text
|
||||
style={[cardStyles.normalText, isRead && cardStyles.mutedText]}
|
||||
>
|
||||
<Text
|
||||
numberOfLines={1}
|
||||
style={isRead ? cardStyles.mutedText : cardStyles.normalText}
|
||||
>
|
||||
<Icon name="megaphone" />{' '}
|
||||
</Text>
|
||||
{body}
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
)
|
||||
}
|
||||
|
||||
export default ReleaseRow
|
||||
48
src/components/cards/partials/rows/RepositoryListRow.tsx
Normal file
48
src/components/cards/partials/rows/RepositoryListRow.tsx
Normal file
@@ -0,0 +1,48 @@
|
||||
import React from 'react'
|
||||
|
||||
import RepositoryRow from './RepositoryRow'
|
||||
import RowList from './RowList'
|
||||
|
||||
import { IGitHubRepo, ITheme } from '../../../../types'
|
||||
import { getOwnerAndRepo } from '../../../../utils/helpers/github/shared'
|
||||
import { getRepoFullNameFromObject } from '../../../../utils/helpers/github/url'
|
||||
|
||||
export interface IProps {
|
||||
isForcePush?: boolean
|
||||
isFork?: boolean
|
||||
isPush?: boolean
|
||||
isRead?: boolean
|
||||
maxHeight?: number
|
||||
repos: IGitHubRepo[]
|
||||
theme: ITheme
|
||||
}
|
||||
|
||||
export default class RepositoryListRow extends React.PureComponent<IProps> {
|
||||
renderItem({ item: repo }: { item: IGitHubRepo }) {
|
||||
if (!(repo && repo.id)) return null
|
||||
|
||||
const repoFullName = getRepoFullNameFromObject(repo)
|
||||
const { owner: repoOwnerName, repo: repoName } = getOwnerAndRepo(
|
||||
repoFullName,
|
||||
)
|
||||
|
||||
if (!(repoOwnerName && repoName)) return null
|
||||
|
||||
return (
|
||||
<RepositoryRow
|
||||
key={`repo-row-${repo.id}`}
|
||||
{...this.props}
|
||||
ownerName={repoOwnerName!}
|
||||
repositoryName={repoName!}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
render() {
|
||||
const { repos, ...props } = this.props
|
||||
|
||||
if (!(repos && repos.length > 0)) return null
|
||||
|
||||
return <RowList {...props} data={repos} renderItem={this.renderItem} />
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
import React, { SFC } from 'react'
|
||||
import { Text, TouchableOpacity, View } from 'react-native'
|
||||
import Icon from 'react-native-vector-icons/Octicons'
|
||||
|
||||
import Avatar from '../../../common/Avatar'
|
||||
import cardStyles from '../../styles'
|
||||
@@ -7,28 +8,60 @@ import { getRepositoryPressHandler } from './helpers'
|
||||
import rowStyles from './styles'
|
||||
|
||||
export interface IProps {
|
||||
repository: string
|
||||
owner: string
|
||||
isForcePush?: boolean
|
||||
isFork?: boolean
|
||||
isPush?: boolean
|
||||
isRead?: boolean
|
||||
ownerName: string
|
||||
repositoryName: string
|
||||
}
|
||||
|
||||
export interface IState {}
|
||||
|
||||
const RepositoryRow: SFC<IProps> = ({ owner, repository }) => (
|
||||
<View style={rowStyles.container}>
|
||||
<View style={cardStyles.leftColumn}>
|
||||
<Avatar username={owner} small style={cardStyles.avatar} />
|
||||
</View>
|
||||
const RepositoryRow: SFC<IProps> = ({
|
||||
isForcePush,
|
||||
isFork,
|
||||
isPush,
|
||||
isRead,
|
||||
ownerName,
|
||||
repositoryName,
|
||||
}) => {
|
||||
const repoIcon =
|
||||
(isForcePush && 'repo-force-push') ||
|
||||
(isPush && 'repo-push') ||
|
||||
(isFork && 'repo-forked') ||
|
||||
'repo'
|
||||
|
||||
<View style={cardStyles.rightColumn}>
|
||||
<TouchableOpacity
|
||||
onPress={getRepositoryPressHandler(owner, repository)}
|
||||
style={rowStyles.mainContentContainer}
|
||||
>
|
||||
<Text style={rowStyles.repositoryText}>{repository}</Text>
|
||||
<Text style={rowStyles.repositorySecondaryText}> {owner}</Text>
|
||||
</TouchableOpacity>
|
||||
return (
|
||||
<View style={rowStyles.container}>
|
||||
<View style={cardStyles.leftColumn}>
|
||||
<Avatar username={ownerName} small style={cardStyles.avatar} />
|
||||
</View>
|
||||
|
||||
<View style={cardStyles.rightColumn}>
|
||||
<TouchableOpacity
|
||||
onPress={getRepositoryPressHandler(ownerName, repositoryName)}
|
||||
style={rowStyles.mainContentContainer}
|
||||
>
|
||||
<Text
|
||||
numberOfLines={1}
|
||||
style={[cardStyles.normalText, isRead && cardStyles.mutedText]}
|
||||
>
|
||||
<Icon name={repoIcon} />{' '}
|
||||
<Text style={rowStyles.repositoryText}>{repositoryName}</Text>
|
||||
<Text
|
||||
style={[
|
||||
rowStyles.repositorySecondaryText,
|
||||
isRead && cardStyles.mutedText,
|
||||
]}
|
||||
>
|
||||
{` ${ownerName}`}
|
||||
</Text>
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
export default RepositoryRow
|
||||
|
||||
49
src/components/cards/partials/rows/RowList.tsx
Normal file
49
src/components/cards/partials/rows/RowList.tsx
Normal file
@@ -0,0 +1,49 @@
|
||||
import React, { ReactNode, SFC } from 'react'
|
||||
import { ScrollView } from 'react-native'
|
||||
|
||||
import { contentPadding } from '../../../../styles/variables'
|
||||
import { ITheme } from '../../../../types'
|
||||
import TransparentTextOverlay from '../../../common/TransparentTextOverlay'
|
||||
|
||||
export interface IProps {
|
||||
data: any[]
|
||||
maxHeight?: number
|
||||
narrow?: boolean
|
||||
renderItem: ({ item, index }: { item: any; index: number }) => ReactNode
|
||||
theme: ITheme
|
||||
}
|
||||
|
||||
const RowList: SFC<IProps> = ({
|
||||
data,
|
||||
maxHeight = 200,
|
||||
narrow,
|
||||
renderItem,
|
||||
theme,
|
||||
...props
|
||||
}) => {
|
||||
if (!(data && data.length > 0)) return null
|
||||
|
||||
if (data.length === 1) return renderItem({ item: data[0], index: 0 })
|
||||
|
||||
return (
|
||||
<TransparentTextOverlay
|
||||
{...props}
|
||||
color={theme.base02}
|
||||
size={narrow ? contentPadding / 2 : contentPadding}
|
||||
from="vertical"
|
||||
containerStyle={{ flex: 0 }}
|
||||
>
|
||||
<ScrollView
|
||||
style={{ maxHeight }}
|
||||
contentContainerStyle={{
|
||||
paddingBottom: narrow ? contentPadding / 2 : contentPadding,
|
||||
}}
|
||||
alwaysBounceVertical={false}
|
||||
>
|
||||
{data.map((item, index) => renderItem({ item, index }))}
|
||||
</ScrollView>
|
||||
</TransparentTextOverlay>
|
||||
)
|
||||
}
|
||||
|
||||
export default RowList
|
||||
35
src/components/cards/partials/rows/UserListRow.tsx
Normal file
35
src/components/cards/partials/rows/UserListRow.tsx
Normal file
@@ -0,0 +1,35 @@
|
||||
import React from 'react'
|
||||
|
||||
import RowList from './RowList'
|
||||
import UserRow from './UserRow'
|
||||
|
||||
import { IGitHubUser, ITheme } from '../../../../types'
|
||||
|
||||
export interface IProps {
|
||||
isRead?: boolean
|
||||
maxHeight?: number
|
||||
users: IGitHubUser[]
|
||||
theme: ITheme
|
||||
}
|
||||
|
||||
export default class UserListRow extends React.PureComponent<IProps> {
|
||||
renderItem = ({ item: user }: { item: IGitHubUser }) => {
|
||||
if (!(user && user.id && user.login)) return null
|
||||
|
||||
return (
|
||||
<UserRow
|
||||
key={`user-row-${user.id}`}
|
||||
{...this.props}
|
||||
username={user.login}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
render() {
|
||||
const { users, ...props } = this.props
|
||||
|
||||
if (!(users && users.length > 0)) return null
|
||||
|
||||
return <RowList {...props} data={users} renderItem={this.renderItem} />
|
||||
}
|
||||
}
|
||||
@@ -7,12 +7,13 @@ import { getUserPressHandler } from './helpers'
|
||||
import rowStyles from './styles'
|
||||
|
||||
export interface IProps {
|
||||
isRead?: boolean
|
||||
username: string
|
||||
}
|
||||
|
||||
export interface IState {}
|
||||
|
||||
const UserRow: SFC<IProps> = ({ username }) => (
|
||||
const UserRow: SFC<IProps> = ({ isRead, username }) => (
|
||||
<View style={rowStyles.container}>
|
||||
<View style={cardStyles.leftColumn}>
|
||||
<Avatar username={username} small style={cardStyles.avatar} />
|
||||
@@ -23,7 +24,9 @@ const UserRow: SFC<IProps> = ({ username }) => (
|
||||
onPress={getUserPressHandler(username)}
|
||||
style={rowStyles.mainContentContainer}
|
||||
>
|
||||
<Text style={rowStyles.usernameText}>{username}</Text>
|
||||
<Text style={[rowStyles.usernameText, isRead && cardStyles.mutedText]}>
|
||||
{username}
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
36
src/components/cards/partials/rows/WikiPageListRow.tsx
Normal file
36
src/components/cards/partials/rows/WikiPageListRow.tsx
Normal file
@@ -0,0 +1,36 @@
|
||||
import React from 'react'
|
||||
|
||||
import RowList from './RowList'
|
||||
import WikiPageRow from './WikiPageRow'
|
||||
|
||||
import { IGitHubPage, ITheme } from '../../../../types'
|
||||
|
||||
export interface IProps {
|
||||
isRead?: boolean
|
||||
maxHeight?: number
|
||||
pages: IGitHubPage[]
|
||||
theme: ITheme
|
||||
}
|
||||
|
||||
export default class WikiPageListRow extends React.PureComponent<IProps> {
|
||||
renderItem = ({ item: page }: { item: IGitHubPage }) => {
|
||||
if (!(page && page.sha && page.title)) return null
|
||||
|
||||
return (
|
||||
<WikiPageRow
|
||||
key={`page-row-${page.sha}`}
|
||||
{...this.props}
|
||||
title={page.title}
|
||||
url={page.html_url || page.url}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
render() {
|
||||
const { pages, ...props } = this.props
|
||||
|
||||
if (!(pages && pages.length > 0)) return null
|
||||
|
||||
return <RowList {...props} data={pages} renderItem={this.renderItem} />
|
||||
}
|
||||
}
|
||||
44
src/components/cards/partials/rows/WikiPageRow.tsx
Normal file
44
src/components/cards/partials/rows/WikiPageRow.tsx
Normal file
@@ -0,0 +1,44 @@
|
||||
import React, { SFC } from 'react'
|
||||
import { Text, TouchableOpacity, View } from 'react-native'
|
||||
import Icon from 'react-native-vector-icons/Octicons'
|
||||
|
||||
import { trimNewLinesAndSpaces } from '../../../../utils/helpers/shared'
|
||||
import cardStyles from '../../styles'
|
||||
import { getGithubURLPressHandler } from './helpers'
|
||||
import rowStyles from './styles'
|
||||
|
||||
export interface IProps {
|
||||
isRead?: boolean
|
||||
name?: string
|
||||
title: string
|
||||
url: string
|
||||
}
|
||||
|
||||
export interface IState {}
|
||||
|
||||
const WikiPageRow: SFC<IProps> = ({ isRead, name, title: _title, url }) => {
|
||||
const title = trimNewLinesAndSpaces(_title || name)
|
||||
if (!title) return null
|
||||
|
||||
return (
|
||||
<View style={rowStyles.container}>
|
||||
<View style={cardStyles.leftColumn} />
|
||||
|
||||
<View style={cardStyles.rightColumn}>
|
||||
<TouchableOpacity
|
||||
onPress={getGithubURLPressHandler(url)}
|
||||
style={rowStyles.mainContentContainer}
|
||||
>
|
||||
<Text
|
||||
numberOfLines={1}
|
||||
style={[cardStyles.normalText, isRead && cardStyles.mutedText]}
|
||||
>
|
||||
<Icon name="book" /> {title}
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
</View>
|
||||
)
|
||||
}
|
||||
|
||||
export default WikiPageRow
|
||||
@@ -1,17 +1,36 @@
|
||||
import R from 'ramda'
|
||||
import SafariView from 'react-native-safari-view'
|
||||
|
||||
export const getUserPressHandler = R.memoize(
|
||||
(username?: string) =>
|
||||
username
|
||||
? () => SafariView.show({ url: `https://github.com/${username}` })
|
||||
import { fixURL } from '../../../../utils/helpers/github/url'
|
||||
|
||||
const baseURL = 'https://github.com'
|
||||
|
||||
export const getGithubURLPressHandler = R.memoize((url?: string) => {
|
||||
const fixedURL = fixURL(url)
|
||||
return fixedURL ? () => SafariView.show({ url: fixedURL }) : undefined
|
||||
}) as (url?: string) => () => void | undefined
|
||||
|
||||
export const getBranchPressHandler = R.memoize(
|
||||
(ownerName?: string, repositoryName?: string, branch?: string) =>
|
||||
ownerName && repositoryName && branch
|
||||
? getGithubURLPressHandler(
|
||||
`${baseURL}/${ownerName}/${repositoryName}/tree/${branch}`,
|
||||
)
|
||||
: undefined,
|
||||
) as (username?: string) => () => void | undefined
|
||||
) as (
|
||||
ownerName?: string,
|
||||
repositoryName?: string,
|
||||
branch?: string,
|
||||
) => () => void | undefined
|
||||
|
||||
export const getRepositoryPressHandler = R.memoize(
|
||||
(owner?: string, repository?: string) =>
|
||||
owner && repository
|
||||
? () =>
|
||||
SafariView.show({ url: `https://github.com/${owner}/${repository}` })
|
||||
(ownerName?: string, repositoryName?: string) =>
|
||||
ownerName && repositoryName
|
||||
? getGithubURLPressHandler(`${baseURL}/${ownerName}/${repositoryName}`)
|
||||
: undefined,
|
||||
) as (owner?: string, repository?: string) => () => void | undefined
|
||||
) as (owner?: string, repositoryName?: string) => () => void | undefined
|
||||
|
||||
export const getUserPressHandler = R.memoize(
|
||||
(username?: string) =>
|
||||
username ? getGithubURLPressHandler(`${baseURL}/${username}`) : undefined,
|
||||
) as (username?: string) => () => void | undefined
|
||||
|
||||
@@ -3,7 +3,7 @@ import { StyleSheet, TextStyle, ViewStyle } from 'react-native'
|
||||
import theme from '../../../../styles/themes/dark'
|
||||
import {
|
||||
contentPadding,
|
||||
radius,
|
||||
// radius,
|
||||
smallTextSize,
|
||||
} from '../../../../styles/variables'
|
||||
|
||||
@@ -17,12 +17,12 @@ export default StyleSheet.create({
|
||||
mainContentContainer: {
|
||||
alignItems: 'center',
|
||||
borderColor: theme.base01,
|
||||
borderRadius: radius,
|
||||
// borderRadius: radius,
|
||||
// borderWidth: 1,
|
||||
flexDirection: 'row',
|
||||
flexGrow: 1,
|
||||
// paddingHorizontal: contentPadding,
|
||||
paddingVertical: contentPadding / 2,
|
||||
// paddingVertical: contentPadding / 2,
|
||||
} as ViewStyle,
|
||||
|
||||
repositoryText: {
|
||||
|
||||
@@ -18,14 +18,19 @@ export default StyleSheet.create({
|
||||
width: avatarSize,
|
||||
} as ViewStyle,
|
||||
|
||||
avatar: {
|
||||
alignSelf: 'flex-end',
|
||||
} as ImageStyle,
|
||||
leftColumnAlignTop: {
|
||||
alignSelf: 'flex-start',
|
||||
} as ViewStyle,
|
||||
|
||||
rightColumn: {
|
||||
flex: 1,
|
||||
flexDirection: 'row',
|
||||
} as ViewStyle,
|
||||
|
||||
avatar: {
|
||||
alignSelf: 'flex-end',
|
||||
} as ImageStyle,
|
||||
|
||||
usernameText: {
|
||||
alignSelf: 'center',
|
||||
color: theme.base04,
|
||||
@@ -43,6 +48,14 @@ export default StyleSheet.create({
|
||||
color: theme.base05,
|
||||
} as TextStyle,
|
||||
|
||||
normalText: {
|
||||
color: theme.base04,
|
||||
} as TextStyle,
|
||||
|
||||
smallText: {
|
||||
fontSize: smallTextSize,
|
||||
} as TextStyle,
|
||||
|
||||
descriptionText: {
|
||||
color: theme.base05,
|
||||
lineHeight: 20,
|
||||
|
||||
@@ -12,11 +12,15 @@ import {
|
||||
getUserAvatarByEmail,
|
||||
getUserAvatarByUsername,
|
||||
} from '../../utils/helpers/github/shared'
|
||||
import { getUserPressHandler } from '../cards/partials/rows/helpers'
|
||||
import {
|
||||
getGithubURLPressHandler,
|
||||
getUserPressHandler,
|
||||
} from '../cards/partials/rows/helpers'
|
||||
|
||||
export interface IProps {
|
||||
avatarURL?: string
|
||||
email?: string
|
||||
linkURL?: string
|
||||
size?: number
|
||||
small?: boolean
|
||||
style?: ImageStyle
|
||||
@@ -34,6 +38,7 @@ const styles = StyleSheet.create({
|
||||
const Avatar: SFC<IProps> = ({
|
||||
avatarURL,
|
||||
email,
|
||||
linkURL,
|
||||
size: _size,
|
||||
small,
|
||||
style,
|
||||
@@ -48,7 +53,13 @@ const Avatar: SFC<IProps> = ({
|
||||
if (!uri) return null
|
||||
|
||||
return (
|
||||
<TouchableOpacity onPress={getUserPressHandler(username)}>
|
||||
<TouchableOpacity
|
||||
onPress={
|
||||
username
|
||||
? getUserPressHandler(username)
|
||||
: linkURL ? getGithubURLPressHandler(linkURL) : undefined
|
||||
}
|
||||
>
|
||||
<Image
|
||||
{...props}
|
||||
source={{ uri }}
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
// @flow
|
||||
|
||||
import React, { ReactNode, SFC } from 'react'
|
||||
import {
|
||||
StyleSheet,
|
||||
@@ -39,6 +37,7 @@ const styles = StyleSheet.create({
|
||||
paddingHorizontal: contentPadding,
|
||||
paddingVertical: 2,
|
||||
} as ViewStyle,
|
||||
|
||||
labelText: {
|
||||
fontSize: 14,
|
||||
} as TextStyle,
|
||||
@@ -70,6 +69,7 @@ const Label: SFC<IProps> = ({
|
||||
{...containerProps}
|
||||
>
|
||||
<Text
|
||||
numberOfLines={1}
|
||||
style={[
|
||||
styles.labelText,
|
||||
{
|
||||
@@ -85,7 +85,7 @@ const Label: SFC<IProps> = ({
|
||||
>
|
||||
{Boolean(isPrivate) && (
|
||||
<Text>
|
||||
<Icon name="lock" /> ,
|
||||
<Icon name="lock" />{' '}
|
||||
</Text>
|
||||
)}
|
||||
{children}
|
||||
|
||||
121
src/components/common/TransparentTextOverlay.tsx
Normal file
121
src/components/common/TransparentTextOverlay.tsx
Normal file
@@ -0,0 +1,121 @@
|
||||
import React, { ReactNode, SFC } from 'react'
|
||||
import { View, ViewStyle } from 'react-native'
|
||||
|
||||
import LinearGradient from '../../libs/linear-gradient'
|
||||
import { fade } from '../../utils/helpers/color'
|
||||
|
||||
type From = 'top' | 'bottom' | 'left' | 'right'
|
||||
type FromWithVH = 'vertical' | 'horizontal' | From
|
||||
|
||||
export interface IProps {
|
||||
children?: ReactNode
|
||||
color: string
|
||||
containerStyle?: ViewStyle
|
||||
from: FromWithVH
|
||||
radius?: number
|
||||
size: number
|
||||
style?: ViewStyle
|
||||
}
|
||||
|
||||
function getStyle(from: From, size: number): ViewStyle {
|
||||
switch (from) {
|
||||
case 'top':
|
||||
return {
|
||||
height: size,
|
||||
left: 0,
|
||||
position: 'absolute',
|
||||
right: 0,
|
||||
top: 0,
|
||||
}
|
||||
case 'bottom':
|
||||
return {
|
||||
bottom: 0,
|
||||
height: size,
|
||||
left: 0,
|
||||
position: 'absolute',
|
||||
right: 0,
|
||||
}
|
||||
case 'left':
|
||||
return {
|
||||
bottom: 0,
|
||||
left: 0,
|
||||
position: 'absolute',
|
||||
top: 0,
|
||||
width: size,
|
||||
}
|
||||
case 'right':
|
||||
return {
|
||||
bottom: 0,
|
||||
position: 'absolute',
|
||||
right: 0,
|
||||
top: 0,
|
||||
width: size,
|
||||
}
|
||||
default:
|
||||
return {}
|
||||
}
|
||||
}
|
||||
|
||||
function getProps(from: From, size: number) {
|
||||
switch (from) {
|
||||
case 'top':
|
||||
return { start: { x: 0, y: 1 }, end: { x: 0, y: 0 }, height: size }
|
||||
case 'bottom':
|
||||
return { start: { x: 0, y: 0 }, end: { x: 0, y: 1 }, height: size }
|
||||
case 'left':
|
||||
return { start: { x: 1, y: 0 }, end: { x: 0, y: 0 }, width: size }
|
||||
default:
|
||||
return { start: { x: 0, y: 0 }, end: { x: 1, y: 0 }, width: size }
|
||||
}
|
||||
}
|
||||
|
||||
const GradientLayerOverlay: SFC<IProps & { from: From }> = ({
|
||||
color,
|
||||
from,
|
||||
radius,
|
||||
size,
|
||||
style,
|
||||
...props
|
||||
}) => (
|
||||
<LinearGradient
|
||||
colors={[fade(color, 0), color]}
|
||||
style={[
|
||||
getStyle(from, size),
|
||||
Boolean(radius) && { borderRadius: radius },
|
||||
style,
|
||||
]}
|
||||
{...getProps(from, size)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
|
||||
const TransparentTextOverlay: SFC<IProps> = ({
|
||||
children,
|
||||
containerStyle,
|
||||
from,
|
||||
...props
|
||||
}) => {
|
||||
return (
|
||||
<View style={[{ flex: 1, alignSelf: 'stretch' }, containerStyle]}>
|
||||
{children}
|
||||
|
||||
{(from === 'vertical' || from === 'top') && (
|
||||
<GradientLayerOverlay {...props} from="top" />
|
||||
)}
|
||||
|
||||
{(from === 'vertical' || from === 'bottom') && (
|
||||
<GradientLayerOverlay {...props} from="bottom" />
|
||||
)}
|
||||
|
||||
{(from === 'horizontal' || from === 'left') && (
|
||||
<GradientLayerOverlay {...props} from="left" />
|
||||
)}
|
||||
|
||||
{(from === 'horizontal' || from === 'right') && (
|
||||
<GradientLayerOverlay {...props} from="right" />
|
||||
)}
|
||||
</View>
|
||||
)
|
||||
}
|
||||
|
||||
export default TransparentTextOverlay
|
||||
@@ -96,7 +96,7 @@ const _data: IGitHubEvent[] = [
|
||||
closed_at: null,
|
||||
author_association: 'CONTRIBUTOR',
|
||||
body:
|
||||
'### Is this a bug report?\r\n\r\nYes. In the example `index.js` we have a line `let language = this.props.language...`. However, in `generate.js` and particularly `metadata.js` we are actually setting the permalink on the assumption that the language isn\'t set.\r\n\r\n```\r\nif (languages.length === 1 && !siteConfig.useEnglishUrl) {\r\n metadata.permalink = \'docs/\' + metadata.id + \'.html\';\r\n } else {\r\n metadata.permalink = \'docs/\' + language + \'/\' + metadata.id + \'.html\';\r\n }\r\n```\r\n\r\nBut in the code before this, we are actually setting this.props.language to `en` by default, I think. So we are conflicting.\r\n\r\nThere are a few ways I can fix this, but I need to come up with the best way.\r\n\r\n### Have you read the [Contributing Guidelines]\r\n\r\nYes, of course. I helped right them :)\r\n\r\n### Environment\r\n\r\nN/A\r\n\r\n### Steps to Reproduce\r\n\r\n1. `yarn global add docusaurus-init`\r\n2. `docusaurus-init`\r\n3. `mv docs-examples-from-docusaurus docs` && `mv website/blog-examples-from-docusaurus website/blog`\r\n4. `cd website`\r\n5. `yarn run start`\r\n6. Go to http://localhost:3000\r\n7. Click on the `Example Link` Button\r\n8. See 404.\r\n\r\n### Expected Behavior\r\n\r\nThe button links should go to an actual docs page.\r\n\r\n### Actual Behavior\r\n\r\nThe button links go to a 404-ish page.\r\n\r\n<img width="1324" alt="screenshot 2017-12-17 15 53 41" src="https://user-images.githubusercontent.com/3757713/34085287-1aaa43ce-e343-11e7-9e04-4edb68d232e7.png">\r\n\r\n<img width="563" alt="screenshot 2017-12-17 15 54 00" src="https://user-images.githubusercontent.com/3757713/34085290-2361cc80-e343-11e7-9957-3a7b39114f83.png">\r\n\r\n### Reproducible Demo\r\n\r\nRun the steps above.\r\n',
|
||||
'### Is this a bug report?\r\n\r\nYes. In the example `index.js` we have a line `let language = this.props.language...`. However, in `generate.js` and particularly `metadata.js` we are actually setting the permalink on the assumption that the language isn\'t set.\r\n\r\n```\r\nif (languages.length === 1 && !siteConfig.useEnglishUrl) {\r\n metadata.permalink = \'docs/\' + metadata.id + \'.html\';\r\n } else {\r\n metadata.permalink = \'docs/\' + language + \'/\' + metadata.id + \'.html\';\r\n }\r\n```\r\n\r\nBut in the code before this, we are actually setting this.props.language to `en` by default, I think. So we are conflicting.\r\n\r\nThere are a few ways I can fix this, but I need to come up with the best way.\r\n\r\n### Have you isRead the [Contributing Guidelines]\r\n\r\nYes, of course. I helped right them :)\r\n\r\n### Environment\r\n\r\nN/A\r\n\r\n### Steps to Reproduce\r\n\r\n1. `yarn global add docusaurus-init`\r\n2. `docusaurus-init`\r\n3. `mv docs-examples-from-docusaurus docs` && `mv website/blog-examples-from-docusaurus website/blog`\r\n4. `cd website`\r\n5. `yarn run start`\r\n6. Go to http://localhost:3000\r\n7. Click on the `Example Link` Button\r\n8. See 404.\r\n\r\n### Expected Behavior\r\n\r\nThe button links should go to an actual docs page.\r\n\r\n### Actual Behavior\r\n\r\nThe button links go to a 404-ish page.\r\n\r\n<img width="1324" alt="screenshot 2017-12-17 15 53 41" src="https://user-images.githubusercontent.com/3757713/34085287-1aaa43ce-e343-11e7-9e04-4edb68d232e7.png">\r\n\r\n<img width="563" alt="screenshot 2017-12-17 15 54 00" src="https://user-images.githubusercontent.com/3757713/34085290-2361cc80-e343-11e7-9957-3a7b39114f83.png">\r\n\r\n### Reproducible Demo\r\n\r\nRun the steps above.\r\n',
|
||||
},
|
||||
comment: {
|
||||
url:
|
||||
@@ -148,83 +148,83 @@ const _data: IGitHubEvent[] = [
|
||||
avatar_url: 'https://avatars.githubusercontent.com/u/69631?',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: '6999953726',
|
||||
type: 'PushEvent',
|
||||
actor: {
|
||||
id: 3757713,
|
||||
login: 'JoelMarcey',
|
||||
display_login: 'JoelMarcey',
|
||||
gravatar_id: '',
|
||||
url: 'https://api.github.com/users/JoelMarcey',
|
||||
avatar_url: 'https://avatars.githubusercontent.com/u/3757713?',
|
||||
},
|
||||
repo: {
|
||||
id: 94911145,
|
||||
name: 'facebook/Docusaurus',
|
||||
url: 'https://api.github.com/repos/facebook/Docusaurus',
|
||||
},
|
||||
payload: {
|
||||
push_id: 2201568216,
|
||||
size: 1,
|
||||
distinct_size: 1,
|
||||
ref: 'refs/heads/gh-pages',
|
||||
head: '043929ac2164d24dbe0b87fed506c67cfa0a5846',
|
||||
before: '6b3d635cc6cdde1a84e4ce9bfc2b3fe95f866f43',
|
||||
commits: [
|
||||
{
|
||||
sha: '043929ac2164d24dbe0b87fed506c67cfa0a5846',
|
||||
author: {
|
||||
email: 'docusaurus@users.noreply.github.com',
|
||||
name: 'Website Deployment Script',
|
||||
},
|
||||
message:
|
||||
'Deploy website\n\nDeploy website version based on 6b3d635cc6cdde1a84e4ce9bfc2b3fe95f866f43',
|
||||
distinct: true,
|
||||
url:
|
||||
'https://api.github.com/repos/facebook/Docusaurus/commits/043929ac2164d24dbe0b87fed506c67cfa0a5846',
|
||||
},
|
||||
],
|
||||
},
|
||||
public: true,
|
||||
created_at: '2017-12-18T00:36:40Z',
|
||||
org: {
|
||||
id: 69631,
|
||||
login: 'facebook',
|
||||
gravatar_id: '',
|
||||
url: 'https://api.github.com/orgs/facebook',
|
||||
avatar_url: 'https://avatars.githubusercontent.com/u/69631?',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: '6999952659',
|
||||
type: 'WatchEvent',
|
||||
actor: {
|
||||
id: 16931088,
|
||||
login: 'wagaman',
|
||||
display_login: 'wagaman',
|
||||
gravatar_id: '',
|
||||
url: 'https://api.github.com/users/wagaman',
|
||||
avatar_url: 'https://avatars.githubusercontent.com/u/16931088?',
|
||||
},
|
||||
repo: {
|
||||
id: 29028775,
|
||||
name: 'facebook/react-native',
|
||||
url: 'https://api.github.com/repos/facebook/react-native',
|
||||
},
|
||||
payload: {
|
||||
action: 'started',
|
||||
},
|
||||
public: true,
|
||||
created_at: '2017-12-18T00:35:54Z',
|
||||
org: {
|
||||
id: 69631,
|
||||
login: 'facebook',
|
||||
gravatar_id: '',
|
||||
url: 'https://api.github.com/orgs/facebook',
|
||||
avatar_url: 'https://avatars.githubusercontent.com/u/69631?',
|
||||
},
|
||||
},
|
||||
// {
|
||||
// id: '6999953726',
|
||||
// type: 'PushEvent',
|
||||
// actor: {
|
||||
// id: 3757713,
|
||||
// login: 'JoelMarcey',
|
||||
// display_login: 'JoelMarcey',
|
||||
// gravatar_id: '',
|
||||
// url: 'https://api.github.com/users/JoelMarcey',
|
||||
// avatar_url: 'https://avatars.githubusercontent.com/u/3757713?',
|
||||
// },
|
||||
// repo: {
|
||||
// id: 94911145,
|
||||
// name: 'facebook/Docusaurus',
|
||||
// url: 'https://api.github.com/repos/facebook/Docusaurus',
|
||||
// },
|
||||
// payload: {
|
||||
// push_id: 2201568216,
|
||||
// size: 1,
|
||||
// distinct_size: 1,
|
||||
// ref: 'refs/heads/gh-pages',
|
||||
// head: '043929ac2164d24dbe0b87fed506c67cfa0a5846',
|
||||
// before: '6b3d635cc6cdde1a84e4ce9bfc2b3fe95f866f43',
|
||||
// commits: [
|
||||
// {
|
||||
// sha: '043929ac2164d24dbe0b87fed506c67cfa0a5846',
|
||||
// author: {
|
||||
// email: 'docusaurus@users.noreply.github.com',
|
||||
// name: 'Website Deployment Script',
|
||||
// },
|
||||
// message:
|
||||
// 'Deploy website\n\nDeploy website version based on 6b3d635cc6cdde1a84e4ce9bfc2b3fe95f866f43',
|
||||
// distinct: true,
|
||||
// url:
|
||||
// 'https://api.github.com/repos/facebook/Docusaurus/commits/043929ac2164d24dbe0b87fed506c67cfa0a5846',
|
||||
// },
|
||||
// ],
|
||||
// },
|
||||
// public: true,
|
||||
// created_at: '2017-12-18T00:36:40Z',
|
||||
// org: {
|
||||
// id: 69631,
|
||||
// login: 'facebook',
|
||||
// gravatar_id: '',
|
||||
// url: 'https://api.github.com/orgs/facebook',
|
||||
// avatar_url: 'https://avatars.githubusercontent.com/u/69631?',
|
||||
// },
|
||||
// },
|
||||
// {
|
||||
// id: '6999952659',
|
||||
// type: 'WatchEvent',
|
||||
// actor: {
|
||||
// id: 16931088,
|
||||
// login: 'wagaman',
|
||||
// display_login: 'wagaman',
|
||||
// gravatar_id: '',
|
||||
// url: 'https://api.github.com/users/wagaman',
|
||||
// avatar_url: 'https://avatars.githubusercontent.com/u/16931088?',
|
||||
// },
|
||||
// repo: {
|
||||
// id: 29028775,
|
||||
// name: 'facebook/react-native',
|
||||
// url: 'https://api.github.com/repos/facebook/react-native',
|
||||
// },
|
||||
// payload: {
|
||||
// action: 'started',
|
||||
// },
|
||||
// public: true,
|
||||
// created_at: '2017-12-18T00:35:54Z',
|
||||
// org: {
|
||||
// id: 69631,
|
||||
// login: 'facebook',
|
||||
// gravatar_id: '',
|
||||
// url: 'https://api.github.com/orgs/facebook',
|
||||
// avatar_url: 'https://avatars.githubusercontent.com/u/69631?',
|
||||
// },
|
||||
// },
|
||||
{
|
||||
id: '6999952360',
|
||||
type: 'PushEvent',
|
||||
|
||||
4
src/libs/linear-gradient/index.tsx
Normal file
4
src/libs/linear-gradient/index.tsx
Normal file
@@ -0,0 +1,4 @@
|
||||
import LinearGradient from 'react-native-linear-gradient'
|
||||
|
||||
export * from 'react-native-linear-gradient'
|
||||
export default LinearGradient
|
||||
30
src/libs/linear-gradient/index.web.tsx
Normal file
30
src/libs/linear-gradient/index.web.tsx
Normal file
@@ -0,0 +1,30 @@
|
||||
import React, { SFC } from 'react'
|
||||
import { PointProperties, View, ViewStyle } from 'react-native'
|
||||
|
||||
export interface IProps {
|
||||
colors: string[]
|
||||
end: PointProperties
|
||||
height: number
|
||||
locations: string[]
|
||||
start: PointProperties
|
||||
style?: ViewStyle
|
||||
width: number
|
||||
}
|
||||
|
||||
const radToDeg = (angle: number) => angle * (180 / Math.PI)
|
||||
const pointsToAngle = (p1: PointProperties, p2: PointProperties) =>
|
||||
radToDeg(Math.atan2(p2.y - p1.y, p2.x - p1.x)) + 90
|
||||
|
||||
const propsToDeg = ({ start, end }: IProps) => `${pointsToAngle(start, end)}deg`
|
||||
|
||||
const propsToLinearGradient = (props: IProps) =>
|
||||
`linear-gradient(${propsToDeg(props)}, ${props.colors.join(', ')})`
|
||||
|
||||
const LinearGradient: SFC<IProps> = props => (
|
||||
<View
|
||||
{...props}
|
||||
style={[props.style, { backgroundColor: propsToLinearGradient(props) }]}
|
||||
/>
|
||||
)
|
||||
|
||||
export default LinearGradient
|
||||
@@ -1,5 +1,5 @@
|
||||
import React from 'react'
|
||||
import { Animated, StyleSheet, Text } from 'react-native'
|
||||
import { Animated, StyleSheet, Text, TextStyle, ViewStyle } from 'react-native'
|
||||
import { RectButton, Swipeable } from 'react-native-gesture-handler'
|
||||
|
||||
import BaseSwipeableRow, {
|
||||
@@ -137,13 +137,14 @@ export default class AppleSwipeableRow extends BaseSwipeableRow<IAction> {
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
baseActionContainer: {
|
||||
flex: 1,
|
||||
justifyContent: 'center',
|
||||
} as ViewStyle,
|
||||
|
||||
actionText: {
|
||||
backgroundColor: 'transparent',
|
||||
fontSize: 16,
|
||||
padding: 10,
|
||||
},
|
||||
baseActionContainer: {
|
||||
flex: 1,
|
||||
justifyContent: 'center',
|
||||
},
|
||||
} as TextStyle,
|
||||
})
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import React from 'react'
|
||||
import { Animated, StyleSheet } from 'react-native'
|
||||
import { Animated, StyleSheet, TextStyle, ViewStyle } from 'react-native'
|
||||
import { RectButton, Swipeable } from 'react-native-gesture-handler'
|
||||
import Icon from 'react-native-vector-icons/MaterialIcons'
|
||||
|
||||
@@ -136,13 +136,14 @@ export default class GoogleSwipeableRow extends BaseSwipeableRow {
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
baseActionContainer: {
|
||||
flex: 1,
|
||||
justifyContent: 'center',
|
||||
} as TextStyle,
|
||||
|
||||
actionIcon: {
|
||||
backgroundColor: 'transparent',
|
||||
marginHorizontal: 10,
|
||||
width: 30,
|
||||
},
|
||||
baseActionContainer: {
|
||||
flex: 1,
|
||||
justifyContent: 'center',
|
||||
},
|
||||
} as ViewStyle,
|
||||
})
|
||||
|
||||
12
src/setup.ts
12
src/setup.ts
@@ -3,12 +3,12 @@ import React from 'react'
|
||||
import { init, startMainApp } from './screens'
|
||||
|
||||
export async function setup() {
|
||||
if (__DEV__) {
|
||||
const { whyDidYouUpdate } = require('why-did-you-update')
|
||||
whyDidYouUpdate(React, {
|
||||
exclude: /[^a-zA-Z0-9]|CellRenderer|Icon|Swipeable/,
|
||||
})
|
||||
}
|
||||
// if (__DEV__) {
|
||||
// const { whyDidYouUpdate } = require('why-did-you-update')
|
||||
// whyDidYouUpdate(React, {
|
||||
// exclude: /[^a-zA-Z0-9]|CellRenderer|Icon|Swipeable/,
|
||||
// })
|
||||
// }
|
||||
|
||||
await init()
|
||||
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
import { StyleSheet, ViewStyle } from 'react-native'
|
||||
|
||||
export default StyleSheet.create({
|
||||
full: {
|
||||
flex: 1,
|
||||
} as ViewStyle,
|
||||
|
||||
horizontal: {
|
||||
flexDirection: 'row',
|
||||
} as ViewStyle,
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import Platform from '../../libs/platform'
|
||||
|
||||
import { ITheme } from '../../types'
|
||||
import * as base from './base'
|
||||
|
||||
export const base00 = '#141c26' // page background
|
||||
@@ -57,4 +58,4 @@ export default {
|
||||
invert: () => require('./light').default, // tslint:disable-line
|
||||
isDark: true,
|
||||
name: 'dark-blue',
|
||||
}
|
||||
} as ITheme
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { Platform } from 'react-native'
|
||||
|
||||
import { ITheme } from '../../types'
|
||||
import { fade } from '../../utils/helpers/color'
|
||||
import { mutedOpacity } from '../variables'
|
||||
import * as base from './base'
|
||||
@@ -59,4 +60,4 @@ export default {
|
||||
invert: () => require('./light').default, // tslint:disable-line
|
||||
isDark: true,
|
||||
name: 'dark',
|
||||
}
|
||||
} as ITheme
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { Platform } from 'react-native'
|
||||
|
||||
import { ITheme } from '../../types'
|
||||
import { lighten } from '../../utils/helpers/color'
|
||||
import { mutedOpacity } from '../variables'
|
||||
import * as base from './base'
|
||||
@@ -56,4 +57,4 @@ export default {
|
||||
invert: () => require('./dark').default, // tslint:disable-line
|
||||
isDark: false,
|
||||
name: 'light',
|
||||
}
|
||||
} as ITheme
|
||||
|
||||
@@ -137,6 +137,7 @@ export interface IGitHubRepo {
|
||||
name: string
|
||||
full_name?: string
|
||||
url: string // https://api.github.com/repos/facebook/react
|
||||
html_url: string // https://github.com/facebook/react
|
||||
}
|
||||
|
||||
export interface IGitHubPage {
|
||||
@@ -145,6 +146,23 @@ export interface IGitHubPage {
|
||||
sha: string
|
||||
title: string
|
||||
html_url: string
|
||||
url: string
|
||||
}
|
||||
|
||||
export interface IGitHubRelease {
|
||||
id: number // 1
|
||||
tag_name: string // "v1.0.0"
|
||||
target_commitish: string // "master"
|
||||
name: string // "v1.0.0"
|
||||
body: string // "Description of the release"
|
||||
draft: boolean
|
||||
prerelease: boolean
|
||||
created_at: string // "2013-02-27T19:35:32Z"
|
||||
published_at: string // "2013-02-27T19:35:32Z"
|
||||
author: IGitHubUser
|
||||
assets: any[] // see https://developer.github.com/v3/repos/releases/#get-a-single-release
|
||||
url: string // "https://api.github.com/repos/octocat/Hello-World/releases/1"
|
||||
html_url: string // "https://github.com/octocat/Hello-World/releases/v1.0.0"
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -283,6 +301,8 @@ export interface IIssuesEvent {
|
||||
assignee?: IGitHubUser | null // The optional user who was assigned or unassigned from the issue.
|
||||
label?: IGitHubLabel // The optional label that was added or removed from the issue.
|
||||
}
|
||||
url: string
|
||||
html_url: string
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -401,6 +421,7 @@ export interface IPushEvent {
|
||||
commits: IGitHubCommit[]
|
||||
}
|
||||
public?: boolean
|
||||
forced?: boolean
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -414,7 +435,7 @@ export interface IReleaseEvent {
|
||||
repo: IGitHubRepo
|
||||
payload: {
|
||||
action: 'published'
|
||||
release: object // https://developer.github.com/v3/repos/releases/#get-a-single-release
|
||||
release: IGitHubRelease // https://developer.github.com/v3/repos/releases/#get-a-single-release
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,25 @@ export * from './github'
|
||||
|
||||
export type Theme = '' | 'auto' | 'light' | 'dark' | 'dark-blue'
|
||||
|
||||
export interface IBase16 {
|
||||
base00: string
|
||||
base01: string
|
||||
base02: string
|
||||
base03: string
|
||||
base04: string
|
||||
base05: string
|
||||
base06: string | undefined
|
||||
base07: string
|
||||
base08: string
|
||||
base09: string | undefined
|
||||
base0A: string | undefined
|
||||
base0B: string | undefined
|
||||
base0C: string | undefined
|
||||
base0D: string | undefined
|
||||
base0E: string | undefined
|
||||
base0F: string | undefined
|
||||
}
|
||||
|
||||
export interface IBaseTheme {
|
||||
blue: string
|
||||
blueGray: string
|
||||
@@ -23,21 +42,11 @@ export interface IBaseTheme {
|
||||
yellow: string
|
||||
}
|
||||
|
||||
export interface ITheme extends IBaseTheme {
|
||||
base00: string
|
||||
base01: string
|
||||
base02: string
|
||||
base03: string
|
||||
base04: string
|
||||
base05: string
|
||||
base06: string | undefined
|
||||
base07: string
|
||||
base08: string
|
||||
base09: string | undefined
|
||||
base0A: string | undefined
|
||||
base0B: string | undefined
|
||||
base0C: string | undefined
|
||||
base0D: string | undefined
|
||||
base0E: string | undefined
|
||||
base0F: string | undefined
|
||||
export interface ITheme extends IBaseTheme, IBase16 {
|
||||
cardBackground: string
|
||||
invert: () => string
|
||||
isDark: boolean
|
||||
name: Theme
|
||||
statusBarBackground: string
|
||||
tabBarBackground: string
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ export function getUserAvatarByUsername(
|
||||
: ''
|
||||
}
|
||||
|
||||
export function tryGetUsernameFromGitHubEmail(email: string) {
|
||||
export function tryGetUsernameFromGitHubEmail(email?: string) {
|
||||
if (!email) return ''
|
||||
|
||||
const emailSplit = email.split('@')
|
||||
@@ -54,6 +54,8 @@ export function isPullRequest(issue: IGitHubIssue | IGitHubPullRequest) {
|
||||
export function getOwnerAndRepo(
|
||||
repoFullName: string,
|
||||
): { owner: string | undefined; repo: string | undefined } {
|
||||
if (!repoFullName) return { owner: '', repo: '' }
|
||||
|
||||
const repoSplitedNames = (repoFullName || '')
|
||||
.trim()
|
||||
.split('/')
|
||||
|
||||
132
src/utils/helpers/github/url.ts
Normal file
132
src/utils/helpers/github/url.ts
Normal file
@@ -0,0 +1,132 @@
|
||||
import { IGitHubRepo } from '../../../types'
|
||||
|
||||
export const baseURL = 'https://github.com'
|
||||
|
||||
export function getCommentIdFromUrl(url: string) {
|
||||
if (!url) return null
|
||||
|
||||
const matches = url.match(/\/comments\/([0-9]+)([?].+)?$/)
|
||||
return (matches && matches[1]) || null
|
||||
}
|
||||
|
||||
export function getCommitShaFromUrl(url: string) {
|
||||
if (!url) return null
|
||||
|
||||
const matches = url.match(/\/commits\/([a-zA-Z0-9]+)([?].+)?$/)
|
||||
return (matches && matches[1]) || null
|
||||
}
|
||||
|
||||
export function getIssueOrPullRequestNumberFromUrl(url: string) {
|
||||
if (!url) return null
|
||||
|
||||
const matches = url.match(/\/(issues|pulls)\/([0-9]+)([?].+)?$/)
|
||||
const n = matches && matches[2]
|
||||
|
||||
return (n && parseInt(n, 10)) || null
|
||||
}
|
||||
|
||||
export function getReleaseIdFromUrl(url: string) {
|
||||
if (!url) return null
|
||||
|
||||
const matches = url.match(/\/releases\/([0-9]+)([?].+)?$/)
|
||||
return (matches && matches[1]) || null
|
||||
}
|
||||
|
||||
/* eslint-disable-next-line no-useless-escape */
|
||||
export const getRepoFullNameFromUrl = (url: string): string =>
|
||||
url
|
||||
? (url.match(
|
||||
/(github.com\/(repos\/)?)([a-zA-Z0-9\-._]+\/[a-zA-Z0-9\-._]+[^/#$]?)/i,
|
||||
) || [])[3] || ''
|
||||
: ''
|
||||
|
||||
export const getRepoFullNameFromObject = (repo: IGitHubRepo): string =>
|
||||
(repo &&
|
||||
(repo.full_name ||
|
||||
repo.name ||
|
||||
getRepoFullNameFromUrl(repo.html_url || repo.url))) ||
|
||||
''
|
||||
|
||||
export const getGitHubURLForUser = (user: string) =>
|
||||
user ? `${baseURL}/${user}` : ''
|
||||
|
||||
const objToQueryParams = (obj: { [key: string]: string | number }) =>
|
||||
Object.keys(obj)
|
||||
.map(key => `${key}=${obj[key]}`)
|
||||
.join('&')
|
||||
|
||||
export const getGitHubSearchURL = (queryParams: {
|
||||
[key: string]: string | number
|
||||
}) => (queryParams ? `${baseURL}/search?${objToQueryParams(queryParams)}` : '')
|
||||
|
||||
export const getGitHubURLForBranch = (repoFullName: string, branch: string) =>
|
||||
repoFullName && branch ? `${baseURL}/${repoFullName}/tree/${branch}` : ''
|
||||
|
||||
export function githubHTMLUrlFromAPIUrl(
|
||||
apiURL: string,
|
||||
{ n }: { n?: number } = {},
|
||||
): string {
|
||||
if (!apiURL) return ''
|
||||
|
||||
const [, type, restOfURL] = apiURL.match(
|
||||
'api.github.com/([a-zA-Z]+)/(.*)',
|
||||
) as string[]
|
||||
if (!(type && restOfURL)) return ''
|
||||
|
||||
if (type === 'repos') {
|
||||
const repoFullName = getRepoFullNameFromUrl(apiURL)
|
||||
const [type2, ...restOfURL2] = (
|
||||
apiURL.split(`/repos/${repoFullName}/`)[1] || ''
|
||||
).split('/')
|
||||
|
||||
if (restOfURL2[0]) {
|
||||
switch (type2) {
|
||||
case 'commits':
|
||||
return `${baseURL}/${repoFullName}/commit/${restOfURL2.join('/')}`
|
||||
|
||||
case 'issues':
|
||||
if (restOfURL2[0] === 'comments' && restOfURL2[1]) {
|
||||
return n
|
||||
? `${baseURL}/${repoFullName}/pull/${n}/comments#issuecomment-${
|
||||
restOfURL2[1]
|
||||
}`
|
||||
: ''
|
||||
}
|
||||
|
||||
return `${baseURL}/${repoFullName}/issues/${restOfURL2.join('/')}`
|
||||
|
||||
case 'pulls':
|
||||
if (restOfURL2[0] === 'comments' && restOfURL2[1]) {
|
||||
return n
|
||||
? `${baseURL}/${repoFullName}/pull/${n}/comments#discussion_r${
|
||||
restOfURL2[1]
|
||||
}`
|
||||
: ''
|
||||
}
|
||||
|
||||
return `${baseURL}/${repoFullName}/pull/${restOfURL2.join('/')}`
|
||||
|
||||
case 'releases':
|
||||
// it wont go directly to the release, but to the generic releases page.
|
||||
// we would need to have the tag name to do that.
|
||||
return `${baseURL}/${repoFullName}/releases/?${restOfURL2.join('/')}`
|
||||
|
||||
default:
|
||||
return `${baseURL}/${restOfURL}`
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return `${baseURL}/${restOfURL}`
|
||||
}
|
||||
|
||||
export function fixURL(url?: string) {
|
||||
if (!url) return
|
||||
|
||||
// sometimes the url come like this: '/facebook/react', so we add https://github.com
|
||||
let uri =
|
||||
url[0] === '/' && url.indexOf('github.com') < 0 ? `${baseURL}${url}` : url
|
||||
uri = uri.indexOf('api.github.com') >= 0 ? githubHTMLUrlFromAPIUrl(uri) : uri
|
||||
|
||||
return uri
|
||||
}
|
||||
@@ -18,3 +18,14 @@ export function getSteppedSize(size?: number, sizeSteps = 50) {
|
||||
export function randomBetween(minNumber: number, maxNumber: number) {
|
||||
return Math.floor(Math.random() * maxNumber) + minNumber
|
||||
}
|
||||
|
||||
export function trimNewLinesAndSpaces(text?: string, maxLength: number = 100) {
|
||||
if (!text || typeof text !== 'string') return ''
|
||||
|
||||
let newText = text.replace(/\s+/g, ' ').trim()
|
||||
if (maxLength > 0 && newText.length > maxLength) {
|
||||
newText = `${newText.substr(0, maxLength).trim()}...`
|
||||
}
|
||||
|
||||
return newText
|
||||
}
|
||||
|
||||
@@ -4153,6 +4153,12 @@ react-native-gesture-handler@^1.0.0-alpha.37:
|
||||
invariant "^2.2.2"
|
||||
prop-types "^15.5.10"
|
||||
|
||||
react-native-linear-gradient@^2.4.0:
|
||||
version "2.4.0"
|
||||
resolved "https://registry.yarnpkg.com/react-native-linear-gradient/-/react-native-linear-gradient-2.4.0.tgz#51d8ea12bb72a59bede9edc87b694b16b64cf435"
|
||||
dependencies:
|
||||
prop-types "^15.5.10"
|
||||
|
||||
react-native-navigation@^1.1.334:
|
||||
version "1.1.334"
|
||||
resolved "https://registry.yarnpkg.com/react-native-navigation/-/react-native-navigation-1.1.334.tgz#255cfe35ea5d7e6edd9d3583dd7a65b9d87736bd"
|
||||
|
||||
Reference in New Issue
Block a user