Merge pull request #68 from esteemapp/feature/editorScreen

Feature/editor screen
This commit is contained in:
Feruz M 2018-10-24 11:06:53 +03:00 committed by GitHub
commit 15bf0748be
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
59 changed files with 1545 additions and 7745 deletions

View File

@ -1238,6 +1238,13 @@
remoteRef = 3DAD3EAE1DF850E9000B6D8A /* PBXContainerItemProxy */;
sourceTree = BUILT_PRODUCTS_DIR;
};
478F70212178F4DC00AB7885 /* libReact-Native-Webview-Bridge.a */ = {
isa = PBXReferenceProxy;
fileType = archive.ar;
path = "libReact-Native-Webview-Bridge.a";
remoteRef = 478F70202178F4DC00AB7885 /* PBXContainerItemProxy */;
sourceTree = BUILT_PRODUCTS_DIR;
};
5E9157331DD0AC6500FF2AA8 /* libRCTAnimation.a */ = {
isa = PBXReferenceProxy;
fileType = archive.ar;
@ -1438,11 +1445,6 @@
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
LIBRARY_SEARCH_PATHS = (
"$(inherited)",
"\"$(SRCROOT)/$(TARGET_NAME)\"",
"\"$(SRCROOT)/$(TARGET_NAME)\"",
"\"$(SRCROOT)/$(TARGET_NAME)\"",
"\"$(SRCROOT)/$(TARGET_NAME)\"",
"\"$(SRCROOT)/$(TARGET_NAME)\"",
);
OTHER_LDFLAGS = (
"-ObjC",
@ -1472,11 +1474,6 @@
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
LIBRARY_SEARCH_PATHS = (
"$(inherited)",
"\"$(SRCROOT)/$(TARGET_NAME)\"",
"\"$(SRCROOT)/$(TARGET_NAME)\"",
"\"$(SRCROOT)/$(TARGET_NAME)\"",
"\"$(SRCROOT)/$(TARGET_NAME)\"",
"\"$(SRCROOT)/$(TARGET_NAME)\"",
);
OTHER_LDFLAGS = (
"-ObjC",
@ -1565,11 +1562,6 @@
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
LIBRARY_SEARCH_PATHS = (
"$(inherited)",
"\"$(SRCROOT)/$(TARGET_NAME)\"",
"\"$(SRCROOT)/$(TARGET_NAME)\"",
"\"$(SRCROOT)/$(TARGET_NAME)\"",
"\"$(SRCROOT)/$(TARGET_NAME)\"",
"\"$(SRCROOT)/$(TARGET_NAME)\"",
);
OTHER_LDFLAGS = (
"-ObjC",
@ -1607,11 +1599,6 @@
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
LIBRARY_SEARCH_PATHS = (
"$(inherited)",
"\"$(SRCROOT)/$(TARGET_NAME)\"",
"\"$(SRCROOT)/$(TARGET_NAME)\"",
"\"$(SRCROOT)/$(TARGET_NAME)\"",
"\"$(SRCROOT)/$(TARGET_NAME)\"",
"\"$(SRCROOT)/$(TARGET_NAME)\"",
);
OTHER_LDFLAGS = (
"-ObjC",
@ -1648,11 +1635,6 @@
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
LIBRARY_SEARCH_PATHS = (
"$(inherited)",
"\"$(SRCROOT)/$(TARGET_NAME)\"",
"\"$(SRCROOT)/$(TARGET_NAME)\"",
"\"$(SRCROOT)/$(TARGET_NAME)\"",
"\"$(SRCROOT)/$(TARGET_NAME)\"",
"\"$(SRCROOT)/$(TARGET_NAME)\"",
);
OTHER_LDFLAGS = (
"-ObjC",
@ -1689,11 +1671,6 @@
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
LIBRARY_SEARCH_PATHS = (
"$(inherited)",
"\"$(SRCROOT)/$(TARGET_NAME)\"",
"\"$(SRCROOT)/$(TARGET_NAME)\"",
"\"$(SRCROOT)/$(TARGET_NAME)\"",
"\"$(SRCROOT)/$(TARGET_NAME)\"",
"\"$(SRCROOT)/$(TARGET_NAME)\"",
);
OTHER_LDFLAGS = (
"-ObjC",

View File

@ -5,7 +5,7 @@
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleDisplayName</key>
<string>esteem</string>
<string>eSteem</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
@ -38,7 +38,21 @@
</dict>
</dict>
<key>NSLocationWhenInUseUsageDescription</key>
<string/>
<string></string>
<key>UILaunchStoryboardName</key>
<string>LaunchScreen</string>
<key>UIRequiredDeviceCapabilities</key>
<array>
<string>armv7</string>
</array>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UIViewControllerBasedStatusBarAppearance</key>
<false/>
<key>UIAppFonts</key>
<array>
<string>Entypo.ttf</string>

85
package-lock.json generated
View File

@ -1512,7 +1512,7 @@
"dependencies": {
"chalk": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
"resolved": "http://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
"integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
"requires": {
"ansi-styles": "^2.2.1",
@ -1705,7 +1705,7 @@
},
"babel-plugin-istanbul": {
"version": "4.1.6",
"resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-4.1.6.tgz",
"resolved": "http://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-4.1.6.tgz",
"integrity": "sha512-PWP9FQ1AhZhS01T/4qLSKoHGY/xvkZdVBGlKM/HuxxS3+sC66HhTNR7+MpbO/so/cz/wY94MeSWJuP1hXIPfwQ==",
"dev": true,
"requires": {
@ -1738,7 +1738,7 @@
},
"babel-plugin-syntax-object-rest-spread": {
"version": "6.13.0",
"resolved": "https://registry.npmjs.org/babel-plugin-syntax-object-rest-spread/-/babel-plugin-syntax-object-rest-spread-6.13.0.tgz",
"resolved": "http://registry.npmjs.org/babel-plugin-syntax-object-rest-spread/-/babel-plugin-syntax-object-rest-spread-6.13.0.tgz",
"integrity": "sha1-/WU28rzhODb/o6VFjEkDpZe7O/U="
},
"babel-plugin-syntax-trailing-function-commas": {
@ -2291,7 +2291,7 @@
},
"browserify-aes": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz",
"resolved": "http://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz",
"integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==",
"requires": {
"buffer-xor": "^1.0.3",
@ -2600,7 +2600,7 @@
},
"color": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/color/-/color-1.0.3.tgz",
"resolved": "http://registry.npmjs.org/color/-/color-1.0.3.tgz",
"integrity": "sha1-5I6DLYXxTvaU+0aIEcLVz+cptV0=",
"requires": {
"color-convert": "^1.8.2",
@ -2779,7 +2779,7 @@
},
"create-hash": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz",
"resolved": "http://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz",
"integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==",
"requires": {
"cipher-base": "^1.0.1",
@ -2791,7 +2791,7 @@
},
"create-hmac": {
"version": "1.1.7",
"resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz",
"resolved": "http://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz",
"integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==",
"requires": {
"cipher-base": "^1.0.3",
@ -2985,7 +2985,7 @@
"dependencies": {
"file-type": {
"version": "3.9.0",
"resolved": "https://registry.npmjs.org/file-type/-/file-type-3.9.0.tgz",
"resolved": "http://registry.npmjs.org/file-type/-/file-type-3.9.0.tgz",
"integrity": "sha1-JXoHg4TR24CHvESdEH1SpSZyuek="
},
"get-stream": {
@ -3856,7 +3856,7 @@
},
"events": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/events/-/events-1.1.1.tgz",
"resolved": "http://registry.npmjs.org/events/-/events-1.1.1.tgz",
"integrity": "sha1-nr23Y1rQmccNzEwqH1AEKI6L2SQ="
},
"evp_bytestokey": {
@ -3958,7 +3958,7 @@
},
"external-editor": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/external-editor/-/external-editor-2.2.0.tgz",
"resolved": "http://registry.npmjs.org/external-editor/-/external-editor-2.2.0.tgz",
"integrity": "sha512-bSn6gvGxKt+b7+6TKEv1ZycHleA7aHhRHyAqJyp5pbUFuYYNIzpZnQDk7AsYckyWdEnTeAnay0aCy2aV6iTk9A==",
"requires": {
"chardet": "^0.4.0",
@ -4834,7 +4834,7 @@
},
"get-stream": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz",
"resolved": "http://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz",
"integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ="
},
"get-value": {
@ -5350,7 +5350,7 @@
},
"is-builtin-module": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz",
"resolved": "http://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz",
"integrity": "sha1-VAVy0096wxGfj3bDDLwbHgN6/74=",
"requires": {
"builtin-modules": "^1.0.0"
@ -5495,7 +5495,7 @@
},
"is-obj": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz",
"resolved": "http://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz",
"integrity": "sha1-PkcprB9f3gJc19g6iW2rn09n2w8=",
"dev": true
},
@ -6983,12 +6983,12 @@
},
"json5": {
"version": "0.5.1",
"resolved": "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz",
"resolved": "http://registry.npmjs.org/json5/-/json5-0.5.1.tgz",
"integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE="
},
"jsonfile": {
"version": "2.4.0",
"resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz",
"resolved": "http://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz",
"integrity": "sha1-NzaitCi4e72gzIO1P6PWM6NcKug=",
"requires": {
"graceful-fs": "^4.1.6"
@ -7538,7 +7538,7 @@
"dependencies": {
"chalk": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
"resolved": "http://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
"integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
"dev": true,
"requires": {
@ -7584,7 +7584,7 @@
"dependencies": {
"chalk": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
"resolved": "http://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
"integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
"dev": true,
"requires": {
@ -7634,7 +7634,7 @@
},
"load-json-file": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz",
"resolved": "http://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz",
"integrity": "sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=",
"requires": {
"graceful-fs": "^4.1.2",
@ -7653,9 +7653,9 @@
}
},
"lodash": {
"version": "4.17.10",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.10.tgz",
"integrity": "sha512-UejweD1pDoXu+AD825lWwp4ZGtSwgnpZxb3JDViD7StjQz+Nb/6l093lx4OQ0foGWNRoc19mWy7BzL+UAK2iVg=="
"version": "4.17.11",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz",
"integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg=="
},
"lodash-es": {
"version": "4.17.11",
@ -8406,7 +8406,7 @@
},
"minimist": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
"resolved": "http://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
"integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ="
},
"minipass": {
@ -8454,7 +8454,7 @@
},
"mkdirp": {
"version": "0.5.1",
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
"resolved": "http://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
"integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=",
"requires": {
"minimist": "0.0.8"
@ -8462,7 +8462,7 @@
"dependencies": {
"minimist": {
"version": "0.0.8",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
"resolved": "http://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
"integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0="
}
}
@ -8573,9 +8573,14 @@
"tween-functions": "^1.0.1"
},
"dependencies": {
"lodash": {
"version": "4.17.10",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.10.tgz",
"integrity": "sha512-UejweD1pDoXu+AD825lWwp4ZGtSwgnpZxb3JDViD7StjQz+Nb/6l093lx4OQ0foGWNRoc19mWy7BzL+UAK2iVg=="
},
"react-native-keyboard-aware-scroll-view": {
"version": "0.5.0",
"resolved": "https://registry.npmjs.org/react-native-keyboard-aware-scroll-view/-/react-native-keyboard-aware-scroll-view-0.5.0.tgz",
"resolved": "http://registry.npmjs.org/react-native-keyboard-aware-scroll-view/-/react-native-keyboard-aware-scroll-view-0.5.0.tgz",
"integrity": "sha512-nGXsACZBCiWuwRrZy+UjiSJqb4tZ/6ePHUSY8M+09g4VfNm/ogvvWpwBa6B999NZ6DwhZTKBjVWeZxX9XG8bbQ==",
"requires": {
"prop-types": "^15.6.0",
@ -8979,7 +8984,7 @@
"dependencies": {
"minimist": {
"version": "0.0.10",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz",
"resolved": "http://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz",
"integrity": "sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8="
},
"wordwrap": {
@ -9432,7 +9437,7 @@
},
"regexpp": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/regexpp/-/regexpp-1.1.0.tgz",
"resolved": "http://registry.npmjs.org/regexpp/-/regexpp-1.1.0.tgz",
"integrity": "sha512-LOPw8FpgdQF9etWMaAfG/WRthIdXJGYp4mJ2Jgn/2lpkbod9jPn0t9UqN7AxBOKNfzRbYyVfgc7Vk4t/MpnXgw==",
"dev": true
},
@ -9871,14 +9876,6 @@
"resolved": "https://registry.npmjs.org/react-native-linear-gradient/-/react-native-linear-gradient-2.4.2.tgz",
"integrity": "sha512-6+efUAsLIn8jHwb861ftjNmw0QuIhKCeQ3vBgQvPDWDcdL1M7GbPmOUdATQfoPod+m+UGSjLf8Tez2QwYLAG+A=="
},
"react-native-markdown-editor": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/react-native-markdown-editor/-/react-native-markdown-editor-1.0.1.tgz",
"integrity": "sha512-VUrRvg/Qm40cv5P6keShYQTqtkSk1IZo8RITuuzXldZo1gavOTHcaVe2OE4KHdGiiqrLMbL/mZj9NNt3I8FChA==",
"requires": {
"react-native-markdown-view": "^1.0.0"
}
},
"react-native-markdown-view": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/react-native-markdown-view/-/react-native-markdown-view-1.1.4.tgz",
@ -9967,7 +9964,7 @@
},
"react-native-vector-icons": {
"version": "4.6.0",
"resolved": "https://registry.npmjs.org/react-native-vector-icons/-/react-native-vector-icons-4.6.0.tgz",
"resolved": "http://registry.npmjs.org/react-native-vector-icons/-/react-native-vector-icons-4.6.0.tgz",
"integrity": "sha512-rpfhfPiXCK2PX1nrNhdxSMrEGB/Gw/SvKoPM0G2wAkSoqynnes19K0VYI+Up7DqR1rFIpE4hP2erpT1tNx2tfg==",
"requires": {
"lodash": "^4.0.0",
@ -10067,7 +10064,7 @@
},
"react-redux": {
"version": "5.0.7",
"resolved": "https://registry.npmjs.org/react-redux/-/react-redux-5.0.7.tgz",
"resolved": "http://registry.npmjs.org/react-redux/-/react-redux-5.0.7.tgz",
"integrity": "sha512-5VI8EV5hdgNgyjfmWzBbdrqUkrVRKlyTKk1sGH3jzM2M2Mhj/seQgPXaz6gVAj2lz/nz688AdTqMO18Lr24Zhg==",
"requires": {
"hoist-non-react-statics": "^2.5.0",
@ -10141,7 +10138,7 @@
},
"readable-stream": {
"version": "2.3.6",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
"resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
"integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
"requires": {
"core-util-is": "~1.0.0",
@ -11031,7 +11028,7 @@
},
"sha.js": {
"version": "2.4.11",
"resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz",
"resolved": "http://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz",
"integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==",
"requires": {
"inherits": "^2.0.1",
@ -11546,7 +11543,7 @@
},
"strip-ansi": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
"resolved": "http://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
"integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
"requires": {
"ansi-regex": "^2.0.0"
@ -11746,7 +11743,7 @@
},
"load-json-file": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz",
"resolved": "http://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz",
"integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=",
"dev": true,
"requires": {
@ -11861,7 +11858,7 @@
},
"through": {
"version": "2.3.8",
"resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz",
"resolved": "http://registry.npmjs.org/through/-/through-2.3.8.tgz",
"integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU="
},
"through2": {
@ -12145,7 +12142,7 @@
},
"underscore.string": {
"version": "2.4.0",
"resolved": "https://registry.npmjs.org/underscore.string/-/underscore.string-2.4.0.tgz",
"resolved": "http://registry.npmjs.org/underscore.string/-/underscore.string-2.4.0.tgz",
"integrity": "sha1-jN2PusTi0uoefi6Al8QvRCKA+Fs="
},
"unicode-canonical-property-names-ecmascript": {
@ -12494,7 +12491,7 @@
},
"wrap-ansi": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz",
"resolved": "http://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz",
"integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=",
"requires": {
"string-width": "^1.0.1",

View File

@ -1,7 +1,12 @@
{
"name": "esteem",
"name": "eSteem",
"version": "0.0.1",
"private": true,
"rnpm": {
"assets": [
"./assets/fonts"
]
},
"scripts": {
"start": "node node_modules/react-native/local-cli/cli.js start",
"eject": "node node_modules/react-native/local-cli/cli.js eject",
@ -20,6 +25,7 @@
"@esteemapp/react-native-tags": "^1.3.1",
"crypto-js": "^3.1.9-1",
"dsteem": "^0.10.1",
"lodash": "^4.17.11",
"moment": "^2.22.2",
"native-base": "^2.8.1",
"react": "^16.6.0-alpha.8af6728",
@ -29,7 +35,7 @@
"react-native-html-renderer": "^1.0.0",
"react-native-keyboard-aware-scroll-view": "^0.7.2",
"react-native-linear-gradient": "^2.4.2",
"react-native-markdown-editor": "^1.0.1",
"react-native-markdown-view": "^1.1.4",
"react-native-modal": "^6.5.0",
"react-native-modal-dropdown": "^0.6.2",
"react-native-modal-popover": "0.0.10",

Binary file not shown.

View File

@ -5,7 +5,15 @@ import NoPost from './view/noPostView';
import PostPlaceHolder from './view/postPlaceHolderView';
import TextWithIcon from './view/textWithIconView';
import WalletLineItem from './view/walletLineItemView';
import Chip from './view/chipView';
export {
Card, GrayWrapper, LineBreak, NoPost, PostPlaceHolder, TextWithIcon, WalletLineItem,
Card,
GrayWrapper,
Chip,
LineBreak,
NoPost,
PostPlaceHolder,
TextWithIcon,
WalletLineItem,
};

View File

@ -0,0 +1,17 @@
import EStyleSheet from 'react-native-extended-stylesheet';
export default EStyleSheet.create({
textInput: {
color: '$white',
fontSize: 10,
backgroundColor: '#c1c5c7',
borderRadius: 50,
maxHeight: 18,
padding: 5,
paddingHorizontal: 10,
marginRight: 8,
},
isPin: {
backgroundColor: '$primaryBlue',
},
});

View File

@ -0,0 +1,16 @@
import React, { Fragment } from 'react';
import { TextInput } from 'react-native';
import styles from './chipStyle';
const Chip = props => (
<Fragment>
<TextInput
style={[styles.textInput, props.isPin && styles.isPin]}
onChangeText={text => props.handleOnChange(text)}
onBlur={() => props.handleOnBlur()}
{...props}
/>
</Fragment>
);
export default Chip;

View File

@ -1,14 +1,14 @@
import EStyleSheet from "react-native-extended-stylesheet";
import EStyleSheet from 'react-native-extended-stylesheet';
export default EStyleSheet.create({
circleButton: {
alignItems: "center",
backgroundColor: "$white",
alignItems: 'center',
backgroundColor: '$white',
height: 60,
width: 60,
borderRadius: 60 / 2,
justifyContent: "center",
borderColor: "$primaryBlue",
justifyContent: 'center',
borderColor: '$primaryBlue',
borderWidth: 1,
},
});

View File

@ -3,14 +3,13 @@ import { TouchableWithoutFeedback, Text, View } from 'react-native';
import styles from './textButtonStyles';
const TextButtonView = ({ text, onPress, style }) => (
const TextButtonView = ({
text, onPress, style, textStyle,
}) => (
<Fragment>
<TouchableWithoutFeedback
style={[styles.button, style]}
onPress={() => onPress && onPress()}
>
<View>
<Text style={styles.buttonText}>{text}</Text>
<TouchableWithoutFeedback style={[styles.button]} onPress={() => onPress && onPress()}>
<View style={style}>
<Text style={[styles.buttonText, textStyle]}>{text}</Text>
</View>
</TouchableWithoutFeedback>
</Fragment>

View File

@ -8,14 +8,14 @@ export default EStyleSheet.create({
alignSelf: 'flex-start',
height: 35,
},
dropdownText: {
fontSize: 9,
color: '$primaryDarkGray',
marginLeft: 25,
},
// dropdownText: {
// fontSize: 9,
// color: '$primaryDarkGray',
// marginLeft: 25,
// },
dropdownIcon: {
fontSize: 18,
color:"$iconColor",
color: '$iconColor',
marginLeft: 7,
marginTop: 1,
},

View File

@ -30,15 +30,16 @@ const renderDropdownRow = (rowData, rowID, highlighted) => (
);
const DropdownButtonView = ({
defaultText,
iconName,
options,
onSelect,
defaultIndex,
children,
style,
isHasChildIcon,
childIconWrapperStyle,
children,
defaultIndex,
defaultText,
iconStyle,
iconName,
isHasChildIcon,
onSelect,
options,
style,
}) => (
<View style={styles.container}>
<ModalDropdown
@ -56,7 +57,10 @@ const DropdownButtonView = ({
>
{isHasChildIcon && (
<View style={[styles.iconWrapper, childIconWrapperStyle && childIconWrapperStyle]}>
<Ionicons style={styles.dropdownIcon} name={!iconName ? 'md-arrow-dropdown' : iconName} />
<Ionicons
style={[styles.dropdownIcon, iconStyle]}
name={!iconName ? 'md-arrow-dropdown' : iconName}
/>
</View>
)}
</ModalDropdown>

View File

@ -0,0 +1,5 @@
import TitleArea from './titleArea/view/titleAreaView';
import TagArea from './tagArea/view/tagAreaView';
import TextArea from './textArea/view/textAreaView';
export { TitleArea, TagArea, TextArea };

View File

@ -0,0 +1,21 @@
import EStyleSheet from 'react-native-extended-stylesheet';
export default EStyleSheet.create({
textInput: {
color: '$white',
fontSize: 10,
backgroundColor: '#c1c5c7',
borderRadius: 50,
maxHeight: 18,
padding: 5,
paddingHorizontal: 10,
marginRight: 8,
},
tagWrapper: {
flexDirection: 'row',
marginTop: 14,
},
firstTag: {
backgroundColor: '$primaryBlue',
},
});

View File

@ -0,0 +1,105 @@
import React, { Component } from 'react';
import { View } from 'react-native';
// Constants
// Components
import { Chip } from '../../../basicUIElements';
// Styles
import styles from './tagAreaStyles';
import globalStyles from '../../../../globalStyles';
export default class TagAreaView extends Component {
/* Props
* ------------------------------------------------
* @prop { type } name - Description....
*/
constructor(props) {
super(props);
this.state = {
currentText: '',
chips: [' '],
chipsCount: props.chipsCount || 5,
};
}
// Component Life Cycles
// Component Functions
_handleOnChange = (text, i) => {
this.setState({ currentText: text.trim() });
if (text.indexOf(' ') > 0 && text) {
this._handleTagAdded();
}
if (!text && i !== 0) {
this._handleTagRemove(i);
}
};
_handleOnBlur = (i) => {
this._handleTagAdded(i);
};
_handleTagAdded = (i) => {
const { currentText, chips, chipsCount } = this.state;
const { handleTagChanged } = this.props;
if (currentText && currentText.trim() && chips && chips.length < chipsCount) {
this.setState({
chips: [...chips, currentText.trim()],
currentText: '',
});
}
if (handleTagChanged && chips.length < chipsCount + 1) {
handleTagChanged([...chips, currentText.trim()]);
}
};
_handleTagRemove = (i) => {
const { chips } = this.state;
const { handleTagChanged } = this.props;
this.setState({
chips: chips.filter((_, _i) => _i !== i),
});
if (handleTagChanged) {
handleTagChanged(chips.filter((_, _i) => _i !== i));
}
};
render() {
const { chipsData, isPreviewActive } = this.props;
const { chips } = this.state;
return (
<View style={globalStyles.containerHorizontal16}>
<View style={styles.tagWrapper}>
{chips.map((chip, i) => (
<Chip
key={i}
refs={(input) => {
this.inputs[i] = input;
}}
isPin={i === 0 && chips[1]}
placeholderTextColor="#fff"
editable={!isPreviewActive}
maxLength={50}
placeholder="tags"
autoFocus={i !== 0 && chips.length - 1 === i}
multiline={false}
handleOnChange={text => this._handleOnChange(text, i)}
handleOnBlur={() => this._handleOnBlur(i)}
blurOnSubmit
autoCapitalize="none"
{...this.props}
/>
))}
</View>
</View>
);
}
}

View File

@ -0,0 +1,8 @@
import EStyleSheet from 'react-native-extended-stylesheet';
export default EStyleSheet.create({
container: {
flex: 1,
marginTop: 16,
},
});

View File

@ -0,0 +1,25 @@
import React, { Component } from 'react';
// Constants
// Components
import { MarkdownEditor } from '../../../markdownEditor';
export default class TextAreaView extends Component {
/* Props
* ------------------------------------------------
* @prop { type } name - Description....
*/
constructor(props) {
super(props);
this.state = {};
}
// Component Life Cycles
// Component Functions
render() {
return <MarkdownEditor {...this.props} />;
}
}

View File

@ -0,0 +1,9 @@
import EStyleSheet from 'react-native-extended-stylesheet';
export default EStyleSheet.create({
textInput: {
color: '$primaryBlack',
fontWeight: 'bold',
fontSize: 24,
},
});

View File

@ -0,0 +1,57 @@
import React, { Component } from 'react';
import { TextInput, View } from 'react-native';
// Constants
// Components
// Styles
import styles from './titleAreaStyles';
import globalStyles from '../../../../globalStyles';
export default class TitleAreaView extends Component {
/* Props
* ------------------------------------------------
* @prop { type } name - Description....
*/
constructor(props) {
super(props);
this.state = {};
}
// Component Life Cycles
// Component Functions
_handleOnChange = (text) => {
const { onChange, handleIsValid, componentID } = this.props;
if (onChange) {
onChange(text);
}
if (handleIsValid) {
handleIsValid(componentID, !!(text && text.length));
}
};
render() {
const { value, isPreviewActive } = this.props;
return (
<View style={globalStyles.containerHorizontal16}>
<TextInput
style={styles.textInput}
placeholderTextColor="#c1c5c7"
editable={!isPreviewActive}
maxLength={250}
placeholder="Title"
multiline
autoFocus
numberOfLines={4}
onChangeText={text => this._handleOnChange(text)}
value={value}
{...this.props}
/>
</View>
);
}
}

View File

@ -0,0 +1,37 @@
import React, { Component } from 'react';
import { withNavigation } from 'react-navigation';
// Constants
import { default as ROUTES } from '../../../constants/routeNames';
// Components
import { EditorHeaderView } from '..';
class EditorHeaderContainer extends Component {
/* Props
* ------------------------------------------------
* @prop { funtion } handleOnPressPreviewButton - Preview button active handler....
*/
constructor(props) {
super(props);
this.state = {};
}
// Component Life Cycles
// Component Functions
_handleOnPressBackButton = () => {
const { navigation } = this.props;
navigation.navigate(ROUTES.SCREENS.HOME);
};
render() {
return (
<EditorHeaderView handleOnPressBackButton={this._handleOnPressBackButton} {...this.props} />
);
}
}
export default withNavigation(EditorHeaderContainer);

View File

@ -0,0 +1,5 @@
import EditorHeaderView from './view/editorHeaderView';
import EditorHeader from './container/editorHeaderContainer';
export { EditorHeaderView, EditorHeader };
export default EditorHeader;

View File

@ -0,0 +1,43 @@
import EStyleSheet from 'react-native-extended-stylesheet';
export default EStyleSheet.create({
container: {
// flex: 1,
flexDirection: 'row',
justifyContent: 'space-between',
padding: 16,
width: '$deviceWidth',
backgroundColor: '$white',
},
backIcon: {
fontSize: 24,
color: '$iconColor',
},
quickTitle: {
flexGrow: 1,
fontSize: 10,
color: '$iconColor',
marginLeft: 24,
alignSelf: 'center',
},
rightIcon: {
color: '$iconColor',
},
iconButton: {
marginRight: 24,
justifyContent: 'center',
alignSelf: 'center',
},
textButton: {
fontSize: 16,
},
textButtonDisable: {
color: '$iconColor',
},
textButtonEnable: {
color: '$primaryBlue',
},
textButtonWrapper: {
justifyContent: 'center',
},
});

View File

@ -0,0 +1,82 @@
import React, { Component } from 'react';
import { View, SafeAreaView, Text } from 'react-native';
import { TextButton } from '../..';
import { IconButton } from '../../iconButton';
// Constants
// Components
// Styles
import styles from './editorHeaderStyles';
class EditorHeaderView extends Component {
/* Props
* ------------------------------------------------
* @prop { boolean } isFormValid - Righst button propertie
* @prop { string } quickTitle - Left side behind back button text
*/
constructor(props) {
super(props);
this.state = {};
}
// Component Life Cycles
// Component Functions
_handleOnPress = () => {
const { handleOnSubmit } = this.props;
if (handleOnSubmit) {
handleOnSubmit();
}
};
render() {
const {
handleOnPressBackButton,
handleOnPressPreviewButton,
isPreviewActive,
quickTitle,
isFormValid,
} = this.props;
return (
<SafeAreaView>
<View style={styles.container}>
<IconButton
iconStyle={styles.backIcon}
name="md-arrow-back"
onPress={() => handleOnPressBackButton()}
/>
<Text style={styles.quickTitle}>{quickTitle}</Text>
<IconButton
style={styles.iconButton}
iconStyle={styles.rightIcon}
size={20}
name="ios-timer"
/>
<IconButton
style={styles.iconButton}
size={25}
onPress={() => handleOnPressPreviewButton()}
iconStyle={styles.rightIcon}
name={isPreviewActive ? 'ios-eye' : 'ios-eye-off'}
/>
<TextButton
textStyle={[
styles.textButton,
isFormValid ? styles.textButtonEnable : styles.textButtonDisable,
]}
onPress={isFormValid && this._handleOnPress}
style={styles.textButtonWrapper}
text="Publish"
/>
</View>
</SafeAreaView>
);
}
}
export default EditorHeaderView;

View File

@ -0,0 +1,4 @@
import Icon from './view/iconView';
export { Icon };
export default Icon;

View File

View File

@ -0,0 +1,60 @@
import React, { Component } from 'react';
import { Platform } from 'react-native';
import Ionicons from 'react-native-vector-icons/Ionicons';
import MaterialCommunityIcons from 'react-native-vector-icons/MaterialCommunityIcons';
import SimpleLineIcons from 'react-native-vector-icons/SimpleLineIcons';
import FontAwesome from 'react-native-vector-icons/FontAwesome';
import Feather from 'react-native-vector-icons/Feather';
class IconView extends Component {
constructor(props) {
super(props);
this.state = {};
}
// for ios its turn ios-eye-off-outline
// for android its turn to md-off-outline
_getIconName = () => {
const { name, androidName } = this.props;
if (name) {
const isIos = Platform.OS === 'ios';
let iconName;
if (!isIos) {
iconName = androidName || `md-${name.split('ios-')}`;
}
return iconName;
}
return null;
};
_getIcon = () => {
const { iconType } = this.props;
const name = this._getIconName();
switch (iconType) {
case 'Feather':
return <Feather {...this.props} />;
case 'FontAwesome':
return <FontAwesome {...this.props} />;
case 'SimpleLineIcons':
return <SimpleLineIcons {...this.props}>{this.props.children}</SimpleLineIcons>;
case 'MaterialCommunityIcons':
return (
<MaterialCommunityIcons name={name} {...this.props}>
{this.props.children}
</MaterialCommunityIcons>
);
default:
return <Ionicons {...this.props} />;
}
};
render() {
return this._getIcon();
}
}
export default IconView;

View File

@ -1,13 +1,12 @@
import EStyleSheet from "react-native-extended-stylesheet";
import EStyleSheet from 'react-native-extended-stylesheet';
export default EStyleSheet.create({
iconButton: {
width: 30,
height: 30,
borderRadius: 30 / 2,
justifyContent: "center",
},
icon: {
textAlign: "center",
justifyContent: 'center',
alignItems: 'center',
},
icon: {},
});

View File

@ -1,32 +1,43 @@
import React from "react";
import { View, TouchableHighlight } from "react-native";
import Ionicons from "react-native-vector-icons/Ionicons";
import React, { Fragment } from 'react';
import { TouchableHighlight } from 'react-native';
import { Icon } from '../../icon';
import styles from "./iconButtonStyles";
import styles from './iconButtonStyles';
/* Props
* ------------------------------------------------
* @prop { type } name - Description....
*/
const IconButton = ({ name, color, size, onPress, backgroundColor, style }) => (
<View>
const IconButton = ({
name,
color,
size,
onPress,
backgroundColor,
style,
iconStyle,
iconType,
}) => (
<Fragment>
<TouchableHighlight
style={[styles.iconButton, style && style]}
style={[!style && styles.iconButton, style && style]}
onPress={() => onPress && onPress()}
underlayColor={backgroundColor}
underlayColor={backgroundColor || 'white'}
>
<Ionicons
<Icon
style={[
color && { color },
backgroundColor && { backgroundColor },
styles.icon,
color && { color: color },
backgroundColor && { backgroundColor: backgroundColor },
iconStyle && iconStyle,
]}
name={name}
size={size}
iconType={iconType}
/>
</TouchableHighlight>
</View>
</Fragment>
);
export default IconButton;

View File

@ -0,0 +1,4 @@
import MarkdownEditor from './view/markdownEditorView';
export { MarkdownEditor };
export default MarkdownEditor;

View File

@ -0,0 +1,14 @@
import EStyleSheet from 'react-native-extended-stylesheet';
export default EStyleSheet.create({
container: {
flexDirection: 'row',
backgroundColor: '$white',
alignItems: 'center',
height: 48,
shadowOpacity: 0.2,
shadowOffset: {
height: 1.5,
},
},
});

View File

@ -0,0 +1,32 @@
import { replaceBetween } from './utils';
export default ({ getState, item, setState }) => {
let { text } = getState();
const { selection } = getState();
text = text || '';
let newText;
let newSelection;
if (selection.start !== selection.end) {
newText = replaceBetween(
text,
selection,
`${item.prefix} ${text.substring(selection.start, selection.end)}\n`,
);
newSelection = { start: selection.end + 3, end: selection.end + 3 };
} else if (
selection.start === selection.end
&& text.substring(selection.end - 1, selection.end) === '\n'
) {
newText = replaceBetween(text, selection, `${item.prefix} `);
newSelection = { start: selection.start + 2, end: selection.start + 2 };
} else {
newText = replaceBetween(text, selection, `\n${item.prefix} `);
newSelection = { start: selection.start + 3, end: selection.start + 3 };
}
setState({ text: newText }, () => {
setTimeout(() => {
setState({ selection: newSelection });
}, 300);
});
};

View File

@ -0,0 +1,35 @@
import { isStringWebLink, replaceBetween } from './utils';
export const writeUrlTextHere = 'https://example.com';
export const writeTextHereString = 'Text here!';
export default ({ getState, item, setState }) => {
const { selection, text } = getState();
let newText;
let newSelection;
const selectedText = text.substring(selection.start, selection.end);
if (selection.start !== selection.end) {
if (isStringWebLink(selectedText)) {
newText = replaceBetween(text, selection, `[${writeTextHereString}](${selectedText})`);
newSelection = {
start: selection.start + 1,
end: selection.start + 1 + writeTextHereString.length,
};
} else {
newText = replaceBetween(text, selection, `[${selectedText}](${writeUrlTextHere})`);
newSelection = {
start: selection.end + 3,
end: selection.end + 3 + writeUrlTextHere.length,
};
}
} else {
newText = replaceBetween(text, selection, `[${writeTextHereString}](${writeUrlTextHere})`);
newSelection = {
start: selection.start + 1,
end: selection.start + 1 + writeTextHereString.length,
};
}
setState({ text: newText }, () => {
setState({ selection: newSelection });
});
};

View File

@ -0,0 +1,27 @@
import { replaceBetween } from './utils';
export default ({ getState, item, setState }) => {
const { text, selection } = getState();
const newText = replaceBetween(
text,
selection,
item.wrapper.concat(text.substring(selection.start, selection.end), item.wrapper),
);
let newPosition;
if (selection.start === selection.end) {
newPosition = selection.end + item.wrapper.length;
} else {
newPosition = selection.end + item.wrapper.length * 2;
}
const extra = {
selection: {
start: newPosition,
end: newPosition,
},
};
setState({ text: newText }, () => {
setTimeout(() => {
setState({ ...extra });
}, 25);
});
};

View File

@ -0,0 +1,55 @@
import { replaceBetween } from './utils';
export default ({ getState, item, setState }) => {
const { text, selection } = getState();
let newText = replaceBetween(
text,
selection,
`\n${item.wrapper.concat(
'\n',
text.substring(selection.start, selection.end),
'\n',
item.wrapper,
'\n',
)}`,
);
let newPosition;
if (selection.start === selection.end) {
newPosition = selection.end + item.wrapper.length + 2; // +2 For two new lines
newText = replaceBetween(
text,
selection,
`\n${item.wrapper.concat(
'\n',
text.substring(selection.start, selection.end),
'\n',
item.wrapper,
'\n',
)}`,
);
} else {
newPosition = selection.end + item.wrapper.length * 2 + 3; // +3 For three new lines
newText = replaceBetween(
text,
selection,
`${item.wrapper.concat(
'\n',
text.substring(selection.start, selection.end),
'\n',
item.wrapper,
'\n',
)}`,
);
}
const extra = {
selection: {
start: newPosition,
end: newPosition,
},
};
setState({ text: newText }, () => {
setTimeout(() => {
setState({ ...extra });
}, 25);
});
};

View File

@ -0,0 +1,116 @@
import applyWrapFormat from './applyWrapFormat';
import applyWrapFormatNewLines from './applyWrapFormatNewLines';
import applyListFormat from './applyListFormat';
import applyWebLinkFormat from './applyWebLinkFormat';
export default [
{
key: 'B',
title: 'B',
icon: 'bold',
iconType: 'Feather',
wrapper: '**',
onPress: applyWrapFormat,
// style: { fontWeight: 'bold' },
},
{
key: 'H1',
title: 'H1',
icon: 'format-size',
iconType: 'MaterialCommunityIcons',
prefix: '#',
onPress: applyListFormat,
},
{
key: 'L',
title: 'L',
icon: 'list',
iconType: 'Feather',
prefix: '-',
onPress: applyListFormat,
},
{
key: 'C',
title: 'C',
icon: 'ios-code',
wrapper: '`',
onPress: applyWrapFormat,
},
{
key: 'I',
title: 'I',
icon: 'italic',
iconType: 'Feather',
wrapper: '*',
onPress: applyWrapFormat,
},
{
key: 'U',
title: 'U',
icon: 'underline',
iconType: 'Feather',
wrapper: '__',
onPress: applyWrapFormat,
},
{
key: 'S',
title: 'S',
wrapper: '~~',
icon: 'strikethrough',
iconType: 'FontAwesome',
onPress: applyWrapFormat,
},
{
key: '>',
title: '>',
prefix: '>',
icon: 'ios-quote',
onPress: applyListFormat,
},
{
key: 'CC',
title: 'CC',
icon: 'ios-code-working',
wrapper: '```',
onPress: applyWrapFormatNewLines,
},
{
key: 'WEB',
title: 'WEB',
icon: 'link-2',
iconType: 'Feather',
onPress: applyWebLinkFormat,
},
// {
// key: 'H2',
// title: 'H2',
// prefix: '##',
// onPress: applyListFormat,
// },
// {
// key: 'H3',
// title: 'H3',
// prefix: '###',
// onPress: applyListFormat,
// },
// {
// key: 'H4',
// title: 'H4',
// prefix: '####',
// onPress: applyListFormat,
// },
// {
// key: 'H5',
// title: 'H5',
// prefix: '#####',
// onPress: applyListFormat,
// },
// {
// key: 'H6',
// title: 'H6',
// prefix: '######',
// onPress: applyListFormat,
// },
];

View File

@ -0,0 +1,8 @@
import regexValidator from './webLinkValidator';
export const replaceBetween = (text: string, selection: Object, what: string) => text.substring(0, selection.start) + what + text.substring(selection.end);
export const isStringWebLink = (text: string): boolean => {
const pattern = regexValidator;
return pattern.test(text);
};

View File

@ -0,0 +1,45 @@
// Regular Expression for URL validation
//
// Author: Diego Perini
// Updated: 2010/12/05
// License: MIT
//
// Copyright (c) 2010-2013 Diego Perini (http://www.iport.it)
//
export default new RegExp(
'^'
// protocol identifier
+ '(?:(?:https?|ftp)://)'
// user:pass authentication
+ '(?:\\S+(?::\\S*)?@)?'
+ '(?:'
// IP address exclusion
// private & local networks
+ '(?!(?:10|127)(?:\\.\\d{1,3}){3})'
+ '(?!(?:169\\.254|192\\.168)(?:\\.\\d{1,3}){2})'
+ '(?!172\\.(?:1[6-9]|2\\d|3[0-1])(?:\\.\\d{1,3}){2})'
// IP address dotted notation octets
// excludes loopback network 0.0.0.0
// excludes reserved space >= 224.0.0.0
// excludes network & broacast addresses
// (first & last IP address of each class)
+ '(?:[1-9]\\d?|1\\d\\d|2[01]\\d|22[0-3])'
+ '(?:\\.(?:1?\\d{1,2}|2[0-4]\\d|25[0-5])){2}'
+ '(?:\\.(?:[1-9]\\d?|1\\d\\d|2[0-4]\\d|25[0-4]))'
+ '|'
// host name
+ '(?:(?:[a-z\\u00a1-\\uffff0-9]-*)*[a-z\\u00a1-\\uffff0-9]+)'
// domain name
+ '(?:\\.(?:[a-z\\u00a1-\\uffff0-9]-*)*[a-z\\u00a1-\\uffff0-9]+)*'
// TLD identifier
+ '(?:\\.(?:[a-z\\u00a1-\\uffff]{2,}))'
// TLD may end with dot
+ '\\.?'
+ ')'
// port number
+ '(?::\\d{2,5})?'
// resource path
+ '(?:[/?#]\\S*)?'
+ '$',
'i',
);

View File

@ -0,0 +1,56 @@
import EStyleSheet from 'react-native-extended-stylesheet';
export default EStyleSheet.create({
container: {
flex: 1,
flexDirection: 'column',
alignItems: 'stretch',
backgroundColor: '$white',
},
textWrapper: {
flex: 1,
flexDirection: 'column',
fontSize: 12,
marginVertical: 16,
paddingHorizontal: 16,
},
inlinePadding: {
padding: 8,
},
editorButtons: {
flexDirection: 'row',
backgroundColor: '$white',
alignItems: 'center',
justifyContent: 'space-between',
height: 50,
shadowOpacity: 0.2,
shadowOffset: {
height: 1.5,
},
},
leftButtonsWrapper: {
marginLeft: 16,
flexDirection: 'row',
alignItems: 'center',
maxWidth: '$deviceWidth / 1.85',
},
rightButtonsWrapper: {
marginRight: 16,
flexDirection: 'row',
alignItems: 'center',
},
editorButton: {
color: '$primaryDarkGray',
paddingRight: 22,
height: 24,
},
dropdownStyle: {
marginRight: 8,
},
rightIcons: {
paddingRight: 21,
},
dropdownIconStyle: {
color: '$primaryDarkGray',
},
});

View File

@ -0,0 +1,152 @@
import React, { Component } from 'react';
import {
View, TextInput, KeyboardAvoidingView, ScrollView, FlatList,
} from 'react-native';
import { MarkdownView } from 'react-native-markdown-view';
// Components
import Formats from './formats/formats';
import { IconButton } from '../../iconButton';
import { DropdownButton } from '../../dropdownButton';
// Styles
import styles from './markdownEditorStyles';
import previewStyles from './markdownPreviewStyles';
export default class MarkdownEditorView extends Component {
constructor(props) {
super(props);
this.state = {
text: '',
selection: { start: 0, end: 0 },
};
}
componentDidMount() {
this.textInput.focus();
}
changeText = (input) => {
const {
onChange, handleOnTextChange, handleIsValid, componentID,
} = this.props;
this.setState({ text: input });
if (onChange) {
onChange(input);
}
if (handleIsValid) {
handleIsValid(componentID, !!(input && input.length));
}
handleOnTextChange && handleOnTextChange(input);
};
_handleOnSelectionChange = (event) => {
this.setState({
selection: event.nativeEvent.selection,
});
};
_getState = () => {
this.setState({
selection: {
start: 1,
end: 1,
},
});
return this.state;
};
_renderPreview = () => {
const { text } = this.state;
return (
<View style={styles.textWrapper}>
<ScrollView removeClippedSubviews>
<MarkdownView styles={previewStyles}>{text === '' ? '...' : text}</MarkdownView>
</ScrollView>
</View>
);
};
_renderMarkupButton = ({ item, getState, setState }) => (
<View style={styles.buttonWrapper}>
<IconButton
size={20}
style={styles.editorButton}
iconType={item.iconType}
name={item.icon}
onPress={() => item.onPress({ getState, setState, item })}
/>
</View>
);
_renderEditorButtons = ({ getState, setState }) => (
<View style={styles.editorButtons}>
<View style={styles.leftButtonsWrapper}>
<FlatList
data={Formats}
keyboardShouldPersistTaps="always"
renderItem={({ item }) => this._renderMarkupButton({ item, getState, setState })}
horizontal
/>
</View>
<View style={styles.rightButtonsWrapper}>
<IconButton
size={20}
style={styles.rightIcons}
iconType="Feather"
name="link-2"
onPress={() => Formats[9].onPress({ getState, setState })}
/>
<IconButton style={styles.rightIcons} size={20} iconType="Feather" name="image" />
<DropdownButton
style={styles.dropdownStyle}
options={['option1', 'option2', 'option3', 'option4']}
iconName="md-more"
iconStyle={styles.dropdownIconStyle}
isHasChildIcon
/>
</View>
</View>
);
render() {
const { isPreviewActive } = this.props;
const { text, selection } = this.state;
return (
<KeyboardAvoidingView style={styles.container} behavior="padding">
{!isPreviewActive ? (
<TextInput
multiline
onChangeText={text => this.changeText(text)}
onSelectionChange={this._handleOnSelectionChange}
placeholder="What would you like to write about today?"
placeholderTextColor="#c1c5c7"
ref={textInput => (this.textInput = textInput)}
selection={selection}
selectionColor="#357ce6"
style={styles.textWrapper}
underlineColorAndroid="transparent"
value={text}
{...this.props}
/>
) : (
this._renderPreview()
)}
{!isPreviewActive
&& this._renderEditorButtons({
getState: this._getState,
setState: (state, callback) => {
this.textInput.focus();
this.setState(state, callback);
},
})}
</KeyboardAvoidingView>
);
}
}

View File

@ -0,0 +1,16 @@
export const markdownPreviewStyles = {
heading1: {
fontSize: 24,
color: 'red',
backgroundColor: 'red',
},
link: {
color: 'pink',
},
mailTo: {
color: 'orange',
},
text: {
color: '#555555',
},
};

View File

@ -0,0 +1,31 @@
import React from 'react';
import {
FlatList, TouchableOpacity, Text, View,
} from 'react-native';
import Formats from './formats/formats';
import styles from './editorBarStyles';
const FOREGROUND_COLOR = '#788187';
const defaultStyles = { padding: 8, color: FOREGROUND_COLOR, fontSize: 16 };
const defaultMarkdownButton = ({ item, getState, setState }) => (
<TouchableOpacity onPress={() => item.onPress({ getState, setState, item })}>
<Text style={[defaultStyles, item.style]}>{item.title}</Text>
</TouchableOpacity>
);
export const renderEditorButtons = ({ getState, setState }, formats, markdownButton) => (
<View style={styles.container}>
<FlatList
data={formats || Formats}
keyboardShouldPersistTaps="always"
renderItem={({ item, index }) => (markdownButton
? markdownButton({ item, getState, setState })
: defaultMarkdownButton({ item, getState, setState }))
}
horizontal
/>
</View>
);

View File

@ -1,15 +1,13 @@
import React, { Fragment, Component } from "react";
import { View } from "react-native";
import React, { Component } from 'react';
import { View } from 'react-native';
import { CircularButton, IconButton } from "../../";
import { CircularButton, IconButton } from '../..';
import styles from "./numericKeyboardStyles";
import styles from './numericKeyboardStyles';
class NumericKeyboard extends Component {
/* Props
*
* @prop { func } onPress - Function will trigger when any button clicked.
*
*/
constructor(props) {
super(props);
@ -20,7 +18,7 @@ class NumericKeyboard extends Component {
// Component Functions
_handleOnPress = value => {
_handleOnPress = (value) => {
alert(value);
};
@ -98,7 +96,7 @@ class NumericKeyboard extends Component {
/>
<IconButton
handleOnPress={() => onPress && onPress("clear")}
handleOnPress={() => onPress && onPress('clear')}
isCircle
style={styles.iconButton}
name="close"

View File

@ -0,0 +1,28 @@
import React, { Component } from 'react';
import { withNavigation } from 'react-navigation';
// Components
import { PostButtonView } from '..';
class PostButtonContainer extends Component {
constructor(props) {
super(props);
this.state = {};
}
// Component Life Cycle Functions
// Component Functions
_handleSubButtonPress = (route) => {
const { navigation } = this.props;
navigation.navigate(route);
};
render() {
return <PostButtonView handleSubButtonPress={this._handleSubButtonPress} {...this.props} />;
}
}
export default withNavigation(PostButtonContainer);

View File

@ -1,4 +1,5 @@
import PostButton from './view/postButtonView';
import PostButtonView from './view/postButtonView';
import PostButton from './container/postButtonContainer';
export { PostButton };
export { PostButtonView, PostButton };
export default PostButton;

View File

@ -81,15 +81,7 @@ class PostButtonView extends Component {
outputRange: ['0deg', '45deg'],
});
// const bluring = this.mode.interpolate({
// inputRange: [0, 1],
// outputRange: [10, 5],
// });
// const blurin2 = this.mode.interpolate({
// inputRange: [0, 1],
// outputRange: [0, -20],
// });
const { handleSubButtonPress } = this.props;
return (
<View style={styles.postButtonWrapper}>
@ -108,6 +100,7 @@ class PostButtonView extends Component {
top: secondY,
}}
icon="pencil"
onPress={() => handleSubButtonPress('EditorScreen')}
/>
<SubPostButton
size={SIZE}

View File

@ -0,0 +1,4 @@
import PostForm from './view/postFormView';
export { PostForm };
export default PostForm;

View File

@ -0,0 +1,46 @@
import React, { Component, Fragment } from 'react';
class PostFormView extends Component {
constructor(props) {
super(props);
this.state = {};
}
_handleOnSubmitEditing = (returnKeyType = null, inputElement = null) => {
const { handleOnSubmit, isFormValid } = this.props;
if (isFormValid && handleOnSubmit && returnKeyType === 'done') {
handleOnSubmit();
} else if (returnKeyType === 'next' && inputElement) {
// TODO: its accept current input but its should be next input ref
inputElement.focus();
}
};
_handleOnChange = (componentID, value, isValid = null) => {
const { handleFormUpdate } = this.props;
handleFormUpdate(componentID, value, !!isValid || !!value);
};
render() {
const { children, isFormValid, isPreviewActive } = this.props;
return (
<Fragment>
{React.Children.map(children, (child) => {
if (child) {
return React.cloneElement(child, {
onSubmitEditing: item => this._handleOnSubmitEditing(child.props.returnKeyType, item),
onChange: value => this._handleOnChange(child.props.componentID, value),
returnKeyType: isFormValid ? 'done' : 'next',
isPreviewActive,
});
}
})}
</Fragment>
);
}
}
export default PostFormView;

View File

@ -29,7 +29,7 @@ class SideMenuContainer extends Component {
// Component Functions
_navigateToRoute = (route) => {
_navigateToRoute = (route = null) => {
const { navigation } = this.props;
navigation.navigate(route);
};

View File

@ -28,6 +28,7 @@ class SideMenuView extends Component {
render() {
const { isLoggedIn, userAvatar, navigateToRoute } = this.props;
return (
<View style={styles.container}>
<View style={styles.headerView}>

View File

@ -3,7 +3,9 @@ import { BaseNavigator } from '../navigation';
import { default as ROUTES } from '../constants/routeNames';
// Screens
import { Splash, Login, PinCode } from '../screens';
import {
Editor, Login, PinCode, Splash,
} from '../screens';
// Components
import { SideMenu } from '../components';
@ -23,8 +25,9 @@ const mainNavigation = DrawerNavigator(
);
export default SwitchNavigator({
[ROUTES.SCREENS.SPLASH]: { screen: Splash },
[ROUTES.DRAWER.MAIN]: mainNavigation,
[ROUTES.SCREENS.EDITOR]: { screen: Editor },
[ROUTES.SCREENS.LOGIN]: { screen: Login },
[ROUTES.SCREENS.PINCODE]: { screen: PinCode },
[ROUTES.DRAWER.MAIN]: mainNavigation,
[ROUTES.SCREENS.SPLASH]: { screen: Splash },
});

View File

@ -3,10 +3,11 @@ const DRAWER_SUFFIX = 'Drawer';
export default {
SCREENS: {
SPLASH: `Splash${SCREEN_SUFFIX}`,
EDITOR: `Editor${SCREEN_SUFFIX}`,
HOME: `Home${SCREEN_SUFFIX}`,
LOGIN: `Login${SCREEN_SUFFIX}`,
PINCODE: `PinCode${SCREEN_SUFFIX}`,
HOME: `Home${SCREEN_SUFFIX}`,
SPLASH: `Splash${SCREEN_SUFFIX}`,
},
DRAWER: {
MAIN: `Main${DRAWER_SUFFIX}`,

View File

@ -1,10 +1,11 @@
import EStyleSheet from 'react-native-extended-stylesheet';
export default EStyleSheet.create({
container: {
containerHorizontal16: {
paddingHorizontal: 16,
},
defaultContainer: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
},
title: {},
text: {

View File

@ -0,0 +1,76 @@
import React, { Component } from 'react';
// Services and Actions
import { postContent } from '../../../providers/steem/dsteem';
import { getUserData } from '../../../realm/realm';
// Middleware
// Constants
import { default as ROUTES } from '../../../constants/routeNames';
// Utilities
import { generatePermlink } from '../../../utils/editor';
import { decryptKey } from '../../../utils/crypto';
// Component
import { EditorScreen } from '../screen/editorScreen';
/*
* Props Name Description Value
*@props --> props name here description here Value Type Here
*
*/
class ExampleContainer extends Component {
constructor(props) {
super(props);
this.state = {};
}
// Component Life Cycle Functions
// Component Functions
_submitPost = async (form) => {
const { navigation } = this.props;
let userData;
let postingKey;
const title = form.formFields['title-area'].content;
const permlink = generatePermlink(title);
await getUserData().then((res) => {
userData = res && Array.from(res)[0];
postingKey = decryptKey(userData.postingKey, '1234');
});
if (userData) {
const post = {
body: form.formFields['text-area'].content,
title,
author: userData.username,
permlink: permlink && permlink,
tags: form.tags,
};
postContent(post, postingKey)
.then((result) => {
alert('Your post succesfully shared');
navigation.navigate(ROUTES.SCREENS.HOME);
})
.catch((error) => {
alert(`Opps! there is a problem${error}`);
});
}
};
_handleSubmit = (form) => {
this._submitPost(form);
};
render() {
return <EditorScreen handleOnSubmit={this._handleSubmit} />;
}
}
export default ExampleContainer;

View File

@ -1,188 +0,0 @@
import React from 'react';
import {
Container,
Header,
Left,
Body,
Right,
Button,
Icon,
Title,
Content,
} from 'native-base';
import { MarkdownEditor } from 'react-native-markdown-editor';
import {
StatusBar,
View,
TextInput,
TouchableOpacity,
Text,
} from 'react-native';
import Tags from '@esteemapp/react-native-tags';
import { postContent } from '../../providers/steem/dsteem';
import { getUserData, getAuthStatus } from '../../realm/realm';
import { decryptKey } from '../../utils/crypto';
class EditorPage extends React.Component {
constructor(props) {
super(props);
this.onChangeBody = this.onChangeBody.bind(this);
this.onChangeTitle = this.onChangeTitle.bind(this);
this.onChangeTags = this.onChangeTags.bind(this);
this.state = {
body: '',
title: '',
author: '',
permlink: '',
tags: ['esteem'],
};
}
componentDidMount() {}
onChangeBody = (body) => {
this.setState({
body,
});
};
onChangeTitle = (title) => {
this.setState({
title,
});
};
onChangeTags = (tags) => {
this.setState({
tags,
});
};
generatePermlink = () => {
let title;
title = this.state.title
.replace(/[^\w\s]/gi, '')
.replace(/\s\s+/g, '-')
.replace(/\s/g, '-')
.toLowerCase();
title = `${title
}-id-${
Math.random()
.toString(36)
.substr(2, 16)}`;
return title;
};
submitPost = async () => {
let userData;
let postingKey;
await getUserData().then((res) => {
userData = Array.from(res);
postingKey = decryptKey(userData[0].postingKey, 'pinCode');
});
post = {
body: this.state.body,
title: this.state.title,
author: userData[0].username,
permlink: this.generatePermlink(),
tags: this.state.tags,
};
console.log(post);
postContent(post, postingKey)
.then((result) => {
console.log(result);
})
.catch((error) => {
console.log(error);
});
};
render() {
return (
<Container style={{ flex: 1 }}>
<View style={{ flex: 1, flexDirection: 'column' }}>
<TextInput
placeholder="Title"
onChangeText={title => this.onChangeTitle(title)}
style={{
borderWidth: 1,
borderColor: 'lightgray',
height: 40,
margin: 10,
borderRadius: 10,
flex: 0.08,
}}
/>
<Tags
initialText=""
initialTags={this.state.tags}
onChangeTags={tags => this.onChangeTags(tags)}
onTagLongPress={(index, tagLabel, event, deleted) => console.log(
index,
tagLabel,
event,
deleted ? 'deleted' : 'not deleted',
)
}
containerStyle={{ justifyContent: 'center' }}
inputStyle={{ backgroundColor: 'white' }}
maxNumberOfTags={5}
tagContainerStyle={{
height: 25,
backgroundColor: '#284b78',
}}
tagTextStyle={{ fontWeight: '600', color: 'white' }}
style={{
borderWidth: 1,
borderColor: 'lightgray',
flex: 0.12,
}}
/>
<View style={{ borderRadius: 10, flex: 0.7 }}>
<MarkdownEditor
onMarkdownChange={(text) => {
this.onChangeBody(text);
}}
/>
</View>
<View style={{ flex: 0.1, flexDirection: 'row' }}>
<View style={{ flex: 0.7 }}>
<Text>Options</Text>
</View>
<View style={{ flex: 0.3 }}>
<TouchableOpacity
onPress={this.submitPost}
style={{
borderRadius: 10,
backgroundColor: '#284b78',
width: 100,
height: 20,
alignItems: 'center',
}}
>
<Text
style={{
color: 'white',
alignSelf: 'center',
}}
>
Submit
</Text>
</TouchableOpacity>
</View>
</View>
</View>
</Container>
);
}
}
export default EditorPage;

View File

@ -0,0 +1,4 @@
import Editor from './container/editorContainer';
export { Editor };
export default Editor;

View File

@ -0,0 +1,117 @@
import React, { Component } from 'react';
import { View } from 'react-native';
// Utils
import { getWordsCount } from '../../../utils/editor';
// Constants
// Components
import { EditorHeader } from '../../../components/editorHeader';
import { TitleArea, TagArea, TextArea } from '../../../components/editorElements';
import { PostForm } from '../../../components/postForm';
// Styles
import globalStyles from '../../../globalStyles';
export class EditorScreen extends Component {
/* Props
* ------------------------------------------------
* @prop { type } name - Description....
*/
constructor(props) {
super(props);
this.state = {
isPreviewActive: false,
wordsCount: null,
formFields: {},
isFormValid: false,
tags: [],
};
}
// Component Life Cycles
// Component Functions
_handleOnPressPreviewButton = () => {
const { isPreviewActive } = this.state;
this.setState({ isPreviewActive: !isPreviewActive });
};
_setWordsCount = (content) => {
const _wordsCount = getWordsCount(content);
const { wordsCount } = this.state;
if (_wordsCount !== wordsCount) {
this.setState({ wordsCount: _wordsCount });
}
};
_handleOnSubmit = () => {
const { handleOnSubmit } = this.props;
const { formFields, tags } = this.state;
if (handleOnSubmit) {
handleOnSubmit({ formFields, tags });
}
};
_handleIsFormValid = () => {
const { formFields, tags } = this.state;
this.setState({
isFormValid:
formFields['title-area']
&& formFields['text-area']
&& formFields['title-area'].isValid
&& formFields['text-area'].isValid
&& tags
&& tags.length > 0,
});
};
_handleFormUpdate = (componentID, content, isValid) => {
const { formFields } = this.state;
const newFormFields = formFields;
newFormFields[componentID] = {
content,
isValid,
};
this.setState({ formFields: newFormFields });
this._handleIsFormValid();
};
_handleOnTagAdded = (tags) => {
this.setState({ tags: tags.filter(tag => tag && tag !== ' ') });
};
render() {
const { isPreviewActive, wordsCount, isFormValid } = this.state;
return (
<View style={globalStyles.defaultContainer}>
<EditorHeader
isPreviewActive={isPreviewActive}
quickTitle={wordsCount > 0 && `${wordsCount} words`}
handleOnPressPreviewButton={this._handleOnPressPreviewButton}
isFormValid={isFormValid}
handleOnSubmit={this._handleOnSubmit}
/>
<PostForm
handleFormUpdate={this._handleFormUpdate}
handleOnSubmit={this._handleOnSubmit}
isPreviewActive={isPreviewActive}
isFormValid={isFormValid}
>
<TitleArea componentID="title-area" />
<TagArea componentID="tag-area" handleTagChanged={this._handleOnTagAdded} />
<TextArea handleOnTextChange={this._setWordsCount} componentID="text-area" />
</PostForm>
</View>
);
}
}

View File

@ -1,9 +1,10 @@
import PinCode from './pinCode';
import Splash from './splash';
import { Editor } from './editor';
import { Home } from './home';
import { Login } from './login';
import { Profile } from './profile';
import { Notification } from './notification';
import { Profile } from './profile';
// import Author from './authorProfile';
// import SideMenu from './sideMenuScreen';
@ -18,12 +19,13 @@ import { Notification } from './notification';
// import { Notification } from './notification';
export {
Editor,
Home,
Login,
PinCode,
Splash,
Profile,
Notification,
PinCode,
Profile,
Splash,
// Author,
// SideMenu,
// Hot,

15
src/utils/editor.js Normal file
View File

@ -0,0 +1,15 @@
export const getWordsCount = text => (text && typeof text === 'string' ? text.replace(/^\s+|\s+$/g, '').split(/\s+/).length : 0);
export const generatePermlink = (text) => {
if (text) {
const re = /[^a-z0-9]+/gi;
const re2 = /^-*|-*$/g;
let permlink = text.replace(re, '-');
permlink = `${permlink.replace(re2, '').toLowerCase()}-id-${Math.random()
.toString(36)
.substr(2, 16)}`;
return permlink;
}
return null;
};

7402
yarn.lock

File diff suppressed because it is too large Load Diff