Merge pull request #1133 from metamaps/feature/topic.follow
Topic Card Design changes (to include 'follows')
This commit is contained in:
commit
a080b82e7f
17 changed files with 269 additions and 227 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -15,6 +15,7 @@ app/assets/javascripts/webpacked
|
|||
|
||||
#secrets and config
|
||||
.env
|
||||
*.swp
|
||||
|
||||
# Ignore bundler config
|
||||
.bundle
|
||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 543 B |
|
@ -1914,14 +1914,10 @@ input.collaboratorSearchField {
|
|||
background-position: -32px 0;
|
||||
}
|
||||
.yourMap .mapPermission:hover {
|
||||
background-image: url(<%= asset_data_uri('arrowperms_sprite.png') %>);
|
||||
cursor: pointer;
|
||||
background-position: -32px 0;
|
||||
}
|
||||
.yourMap .mapPermission.minimize {
|
||||
background-image: url(<%= asset_data_uri('arrowperms_sprite.png') %>) !important;
|
||||
cursor: pointer;
|
||||
background-position: 0 0;
|
||||
}
|
||||
.mapInfoBox .mapPermission .permissionSelect {
|
||||
list-style: none;
|
||||
|
@ -3150,11 +3146,15 @@ script.data-gratipay-username {
|
|||
}
|
||||
|
||||
.topicFollow {
|
||||
text-align: center;
|
||||
height: 48px;
|
||||
line-height: 48px;
|
||||
border-top: 1px solid #BDBDBD;
|
||||
background: #FFF;
|
||||
height: 24px;
|
||||
line-height: 24px;
|
||||
cursor: pointer;
|
||||
font-family: din-regular;
|
||||
font-family: helvetica, sans-serif;
|
||||
float: left;
|
||||
width: 72px;
|
||||
text-align: right;
|
||||
padding: 12px 0;
|
||||
color: #4fb5c0;
|
||||
font-size: 13px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
|
|
@ -1,9 +1,12 @@
|
|||
$mid-gray: #8A8A8A;
|
||||
$mid-gray-opacity: rgba(66, 66, 66, 0.6);
|
||||
|
||||
.nameCounter {
|
||||
position: absolute;
|
||||
bottom: 1px;
|
||||
right: 2px;
|
||||
font-size: 11px;
|
||||
font-family: helvetica;
|
||||
font-family: helvetica, sans-serif;
|
||||
color: #727272;
|
||||
line-height: 11px;
|
||||
display: none;
|
||||
|
@ -42,7 +45,7 @@
|
|||
z-index:2;
|
||||
color: #424242;
|
||||
border-radius:2px;
|
||||
box-shadow: 0px 3px 3px rgba(0,0,0,0.23), 0 3px 3px rgba(0,0,0,0.16);
|
||||
box-shadow: 2px 3px 3px rgba(125, 125, 125, 0.23), -2px -1px 3px rgba(125, 125, 125, 0.16);
|
||||
}
|
||||
|
||||
.text {
|
||||
|
@ -64,7 +67,6 @@
|
|||
display:block;
|
||||
position:relative;
|
||||
width:100%;
|
||||
min-height:360px;
|
||||
z-index: 25;
|
||||
}
|
||||
.CardOnGraph.hasAttachment {
|
||||
|
@ -73,11 +75,10 @@
|
|||
|
||||
.CardOnGraph .title {
|
||||
word-break: break-word;
|
||||
font-size: 18px;
|
||||
line-height: 22px;
|
||||
font-size: 20px;
|
||||
line-height: 24px;
|
||||
display: table;
|
||||
padding: 8px 0 16px;
|
||||
height: 80px;
|
||||
padding: 20px 0;
|
||||
text-align: center;
|
||||
font-family: 'din-regular', sans-serif;
|
||||
width: 300px;
|
||||
|
@ -88,11 +89,6 @@
|
|||
display: table-cell;
|
||||
vertical-align: middle;
|
||||
padding: 0 16px;
|
||||
|
||||
&.riek-editing {
|
||||
position: absolute;
|
||||
top: 32px;
|
||||
}
|
||||
}
|
||||
.canEdit #titleActivator:hover {
|
||||
background-image: url(<%= asset_data_uri('edit.png') %>);
|
||||
|
@ -104,9 +100,8 @@
|
|||
.showcard .title .riek-editing {
|
||||
font-family: 'din-regular', sans-serif;
|
||||
color: #424242;
|
||||
font-size: 18px;
|
||||
line-height: 22px;
|
||||
height: 3em;
|
||||
font-size: 20px;
|
||||
line-height: 24px;
|
||||
padding: 5px 0;
|
||||
width: 100%;
|
||||
margin: 0;
|
||||
|
@ -120,11 +115,19 @@
|
|||
.CardOnGraph .scroll {
|
||||
display:block;
|
||||
padding: 8px 0 8px 16px;
|
||||
height: 152px;
|
||||
font-size: 13px;
|
||||
line-height:15px;
|
||||
font-family: helvetica, sans-serif;
|
||||
overflow-y: auto;
|
||||
|
||||
p.emptyDesc {
|
||||
color: $mid-gray-opacity;
|
||||
}
|
||||
|
||||
a.mdSupport {
|
||||
color: #4fb5c0;
|
||||
font-size: 11px;
|
||||
}
|
||||
}
|
||||
.CardOnGraph.hasAttachment .scroll {
|
||||
height: auto;
|
||||
|
@ -180,7 +183,6 @@
|
|||
margin-top:2px;
|
||||
padding-right: 18px;
|
||||
margin-right: 8px;
|
||||
min-height: 7em;
|
||||
}
|
||||
.canEdit .CardOnGraph .riek_desc:hover {
|
||||
background-image: url(<%= asset_data_uri('edit.png') %>);
|
||||
|
@ -195,9 +197,7 @@
|
|||
|
||||
.CardOnGraph .links {
|
||||
position: relative;
|
||||
border-bottom: 1px solid #BDBDBD;
|
||||
border-top: 1px solid #BDBDBD;
|
||||
background-color: #e0e0e0;
|
||||
z-index: 2;
|
||||
|
||||
.linkItem {
|
||||
float: left;
|
||||
|
@ -213,37 +213,52 @@
|
|||
}
|
||||
|
||||
.icon {
|
||||
position: absolute;
|
||||
z-index: 1;
|
||||
padding: 0;
|
||||
height: 48px;
|
||||
width: 100%;
|
||||
margin-right: 10px;
|
||||
|
||||
.metacodeImage {
|
||||
cursor: move;
|
||||
position: relative;
|
||||
left: -23px;
|
||||
top: 1px;
|
||||
width: 46px;
|
||||
height: 46px;
|
||||
background-size:46px 46px;
|
||||
position: absolute;
|
||||
left: -18px;
|
||||
top: 6px;
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
background-size:36px 36px;
|
||||
background-position:0 0;
|
||||
background-repeat:no-repeat;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.CardOnGraph .info {
|
||||
position: relative;
|
||||
|
||||
.linkItem {
|
||||
float: left;
|
||||
z-index: 1;
|
||||
position: relative;
|
||||
color: $mid-gray-opacity;
|
||||
font-size: 14px;
|
||||
line-height: 14px;
|
||||
|
||||
a {
|
||||
color: $mid-gray-opacity;
|
||||
}
|
||||
}
|
||||
|
||||
.contributor {
|
||||
bottom: 7px;
|
||||
margin-left: 40px;
|
||||
margin-left: 16px;
|
||||
|
||||
.contributorIcon {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
border-radius: 16px;
|
||||
margin: 5px;
|
||||
top: 8px;
|
||||
margin: 5px 5px 5px 0;
|
||||
top: 11px;
|
||||
left: 0;
|
||||
border-radius: 16px;
|
||||
}
|
||||
|
||||
span {
|
||||
|
@ -252,52 +267,34 @@
|
|||
}
|
||||
|
||||
.contributorName {
|
||||
display: none;
|
||||
position: absolute;
|
||||
background: black;
|
||||
text-align: center;
|
||||
color: white;
|
||||
border-radius: 2px;
|
||||
font-family: din-regular;
|
||||
line-height: 15px;
|
||||
font-size: 12px;
|
||||
padding: 3px 5px 2px;
|
||||
margin-top: 20px;
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
width: 97px;
|
||||
padding: 0 8px 0 4px;
|
||||
white-space: nowrap;
|
||||
margin-top: 8px;
|
||||
|
||||
&:before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 26px;
|
||||
left: 10px;
|
||||
margin-top: -30px;
|
||||
width: 0;
|
||||
height: 0;
|
||||
border-bottom: 4px solid #000000;
|
||||
border-left: 5px solid transparent;
|
||||
border-right: 5px solid transparent;
|
||||
}
|
||||
}
|
||||
|
||||
&:hover .contributorName {
|
||||
display: block;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
}
|
||||
|
||||
.mapCount {
|
||||
padding:17px 0 17px 36px;
|
||||
margin-left: 12px;
|
||||
padding:17px 38px 17px 0;
|
||||
width: 22px;
|
||||
text-align: right;
|
||||
|
||||
.mapCountIcon {
|
||||
position: absolute;
|
||||
top: 8px;
|
||||
left: 0;
|
||||
right: 0;
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
background-image: url(<%= asset_data_uri('map32_sprite.png') %>);
|
||||
background-repeat: no-repeat;
|
||||
background-position: 0 0;
|
||||
cursor: pointer;
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
&:hover .mapCountIcon {
|
||||
|
@ -306,18 +303,18 @@
|
|||
|
||||
.tip, .hoverTip {
|
||||
top: 44px;
|
||||
left: 0px;
|
||||
right: 0px;
|
||||
font-size: 12px !important;
|
||||
|
||||
&:before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 26px;
|
||||
left: 10px;
|
||||
right: 10px;
|
||||
margin-top: -30px;
|
||||
width: 0;
|
||||
height: 0;
|
||||
border-bottom: 4px solid #000000;
|
||||
border-bottom: 4px solid $mid-gray;
|
||||
border-left: 5px solid transparent;
|
||||
border-right: 5px solid transparent;
|
||||
}
|
||||
|
@ -327,10 +324,9 @@
|
|||
white-space: nowrap;
|
||||
font-family: 'din-regular';
|
||||
top: 44px;
|
||||
left: 0px;
|
||||
font-size: 12px !important;
|
||||
position: absolute;
|
||||
background: black;
|
||||
background: $mid-gray;
|
||||
color: white;
|
||||
border-radius: 4px;
|
||||
line-height: 17px;
|
||||
|
@ -362,28 +358,31 @@
|
|||
}
|
||||
|
||||
.synapseCount {
|
||||
margin-left: 26px;
|
||||
width: 24px;
|
||||
padding:17px 0 17px 32px;
|
||||
width: 22px;
|
||||
padding:17px 38px 17px 0;
|
||||
text-align: right;
|
||||
margin-right: 4px;
|
||||
|
||||
.synapseCountIcon {
|
||||
position: absolute;
|
||||
top: 8px;
|
||||
left: 0;
|
||||
right: 0;
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
background-image: url(<%= asset_data_uri('synapse32_sprite.png') %>);
|
||||
background-repeat: no-repeat;
|
||||
background-position: 0 0;
|
||||
opacity: 0.6;
|
||||
}
|
||||
hover .synapseCountIcon {
|
||||
background-position: 0 -32px;
|
||||
}
|
||||
.tip {
|
||||
position: absolute;
|
||||
background: black;
|
||||
background: $mid-gray;
|
||||
width: auto;
|
||||
top: 44px;
|
||||
right: 0px;
|
||||
color: white;
|
||||
white-space: nowrap;
|
||||
border-radius: 2px;
|
||||
|
@ -398,10 +397,10 @@
|
|||
content: '';
|
||||
position: absolute;
|
||||
margin-top: -8px;
|
||||
margin-left: 6px;
|
||||
right: 12px;
|
||||
width: 0;
|
||||
height: 0;
|
||||
border-bottom: 4px solid black;
|
||||
border-bottom: 4px solid $mid-gray;
|
||||
border-left: 5px solid transparent;
|
||||
border-right: 5px solid transparent;
|
||||
}
|
||||
|
@ -413,6 +412,10 @@
|
|||
color: #4FC059;
|
||||
}
|
||||
|
||||
.linkItem.mapPerm {
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
.mapPerm {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
|
@ -434,14 +437,10 @@
|
|||
}
|
||||
|
||||
.yourTopic .mapPerm:hover, .yourEdge .mapPerm:hover {
|
||||
background-image: url(<%= asset_data_uri('arrowperms_sprite.png') %>);
|
||||
background-position: -32px 0;
|
||||
cursor:pointer;
|
||||
}
|
||||
.yourTopic .mapPerm.minimize, .yourEdge .mapPerm.minimize {
|
||||
background-image: url(<%= asset_data_uri('arrowperms_sprite.png') %>) !important;
|
||||
background-position: 0 0;
|
||||
cursor: pointer;
|
||||
cursor: pointer;
|
||||
}
|
||||
.mapPerm .permissionSelect {
|
||||
list-style: none;
|
||||
|
@ -477,32 +476,34 @@ cursor: pointer;
|
|||
}
|
||||
|
||||
.CardOnGraph .metacodeTitle {
|
||||
font-style: italic;
|
||||
font-family: 'vinyl';
|
||||
text-transform: uppercase;
|
||||
position: absolute;
|
||||
font-family: 'din-regular';
|
||||
line-height: 24px;
|
||||
height: 26px;
|
||||
font-size: 24px;
|
||||
display: none;
|
||||
width: 90%;
|
||||
padding: 13px 0 9px 10%;
|
||||
background-color: #E0E0E0;
|
||||
font-size: 18px;
|
||||
padding: 13px 24px 9px 24px;
|
||||
color: #424242;
|
||||
width: 120px;
|
||||
max-width: 120px;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
}
|
||||
.permission.canEdit .metacodeTitle {
|
||||
cursor:pointer;
|
||||
}
|
||||
|
||||
.permission.canEdit .expandMetacodeSelect {
|
||||
position: absolute;
|
||||
top: 16px;
|
||||
right: 16px;
|
||||
position: relative;
|
||||
top: 2px;
|
||||
left: 4px;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
background-image: url(<%= asset_data_uri('arrowright_sprite.png') %>);
|
||||
background-repeat: no-repeat;
|
||||
background-position: 0 -32px;
|
||||
display: inline-block;
|
||||
-webkit-transform: rotate(90deg);
|
||||
transform: rotate(90deg);
|
||||
}
|
||||
.permission.canEdit .minimize .expandMetacodeSelect {
|
||||
|
||||
|
@ -519,8 +520,8 @@ cursor: pointer;
|
|||
background: #EAEAEA;
|
||||
white-space: nowrap;
|
||||
position: absolute;
|
||||
left: 300px;
|
||||
top: -1px;
|
||||
top: 48px;
|
||||
box-shadow: 2px 2px 2px rgba(125, 125, 125, 0.23), -2px -1px 3px rgba(125, 125, 125, 0.16);
|
||||
}
|
||||
.CardOnGraph .metacodeSelect ul {
|
||||
position: relative;
|
||||
|
@ -613,9 +614,9 @@ background-color: #E0E0E0;
|
|||
}
|
||||
.CardOnGraph .tip {
|
||||
position: absolute;
|
||||
background: black;
|
||||
background: $mid-gray;
|
||||
top: 35px;
|
||||
left: 0;
|
||||
right: 0;
|
||||
color: white;
|
||||
border-radius: 4px;
|
||||
font-size:15px !important;
|
||||
|
@ -633,7 +634,6 @@ background-color: #E0E0E0;
|
|||
width:100%;
|
||||
height:47px;
|
||||
position: relative;
|
||||
border-top: 1px solid #BDBDBD;
|
||||
}
|
||||
|
||||
.link-adder a {
|
||||
|
@ -695,9 +695,9 @@ background-color: #E0E0E0;
|
|||
}
|
||||
|
||||
#addLinkInput input{
|
||||
padding: 9px 7px 9px 31px;
|
||||
padding: 9px 27px 9px 31px;
|
||||
height: 12px;
|
||||
width: 198px;
|
||||
width: 210px;
|
||||
margin: 0 0 0 0;
|
||||
border: none;
|
||||
outline: none;
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
</script>
|
||||
<%= render :partial => 'layouts/lightboxes' %>
|
||||
<%= render :partial => 'layouts/templates' %>
|
||||
<%= render :partial => 'shared/metacodeBgColors' %>
|
||||
<%= render :partial => 'shared/metacodeCssColors' %>
|
||||
<%= render :partial => 'layouts/googleanalytics' if ENV["GA_TRACKING_CODE"].present? %>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -1,9 +0,0 @@
|
|||
<style>
|
||||
<% Metacode.all.each do |m| %>
|
||||
<% if m.color %>
|
||||
<%= ".mbg" + m.id.to_s + "{" %>
|
||||
<%= "background-color:" + m.color + " !important;" %>
|
||||
<%= "}" %>
|
||||
<% end %>
|
||||
<% end %>
|
||||
</style>
|
10
app/views/shared/_metacodeCssColors.html.erb
Normal file
10
app/views/shared/_metacodeCssColors.html.erb
Normal file
|
@ -0,0 +1,10 @@
|
|||
<style>
|
||||
<% # give text the color of the metacode by adding the class .metacodeColor{metacode-id} %>
|
||||
<% Metacode.all.each do |m| %>
|
||||
<% if m.color %>
|
||||
<%= ".metacodeColor" + m.id.to_s + "{" %>
|
||||
<%= "color:" + m.color + " !important;" %>
|
||||
<%= "}" %>
|
||||
<% end %>
|
||||
<% end %>
|
||||
</style>
|
|
@ -35,7 +35,7 @@ const Map = Backbone.Model.extend({
|
|||
}
|
||||
},
|
||||
isFollowedBy: function(mapper) {
|
||||
return mapper.get('follows') && mapper.get('follows').maps.indexOf(this.get('id')) > -1
|
||||
return mapper && mapper.get('follows') && mapper.get('follows').maps.indexOf(this.get('id')) > -1
|
||||
},
|
||||
getUser: function() {
|
||||
return Mapper.get(this.get('user_id'))
|
||||
|
|
|
@ -48,7 +48,7 @@ const Topic = Backbone.Model.extend({
|
|||
else return false
|
||||
},
|
||||
isFollowedBy: function(mapper) {
|
||||
return mapper.get('follows') && mapper.get('follows').topics.indexOf(this.get('id')) > -1
|
||||
return mapper && mapper.get('follows') && mapper.get('follows').topics.indexOf(this.get('id')) > -1
|
||||
},
|
||||
getDate: function() {},
|
||||
getMetacode: function() {
|
||||
|
|
|
@ -13,6 +13,7 @@ import PropTypes from 'prop-types'
|
|||
|
||||
class MetacodeSelect extends Component {
|
||||
render = () => {
|
||||
if (!this.props.metacodeSets) return null
|
||||
return (
|
||||
<div id="metacodeOptions">
|
||||
<ul>
|
||||
|
|
|
@ -26,7 +26,7 @@ class MdTextArea extends RIETextArea {
|
|||
class Desc extends Component {
|
||||
render = () => {
|
||||
const descHTML = (!this.props.desc && this.props.authorizedToEdit)
|
||||
? '<p>Click to add description...</p>'
|
||||
? '<p class="emptyDesc">Edit the description... (supports markdown)</p>'
|
||||
: Util.mdToHTML(this.props.desc)
|
||||
|
||||
if (this.props.authorizedToEdit) {
|
||||
|
@ -51,6 +51,7 @@ class Desc extends Component {
|
|||
dangerouslySetInnerHTML: { __html: descHTML }
|
||||
}}
|
||||
/>
|
||||
<a className="mdSupport" href="http://commonmark.org/help/" target="_blank">learn markdown</a>
|
||||
<div className="clearfloat"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -3,16 +3,27 @@ import PropTypes from 'prop-types'
|
|||
|
||||
class Follow extends Component {
|
||||
render = () => {
|
||||
const { isFollowing, onTopicFollow } = this.props
|
||||
return <div className='topicFollow' onClick={onTopicFollow}>
|
||||
{isFollowing ? 'Unfollow' : 'Follow'}
|
||||
const { ActiveMapper, isFollowing, onTopicFollow } = this.props
|
||||
function onClick () {
|
||||
if (ActiveMapper) {
|
||||
onTopicFollow()
|
||||
}
|
||||
}
|
||||
let innerValue
|
||||
// only display either option if there is a user signed in
|
||||
if (ActiveMapper) {
|
||||
innerValue = isFollowing ? 'Unfollow' : 'Follow'
|
||||
}
|
||||
return <div className='topicFollow' onClick={onClick}>
|
||||
{innerValue}
|
||||
</div>
|
||||
}
|
||||
}
|
||||
|
||||
Follow.propTypes = {
|
||||
isFollowing: PropTypes.bool,
|
||||
onTopicFollow: PropTypes.func
|
||||
onTopicFollow: PropTypes.func,
|
||||
ActiveMapper: PropTypes.object
|
||||
}
|
||||
|
||||
export default Follow
|
||||
|
|
105
frontend/src/components/TopicCard/Info.js
Normal file
105
frontend/src/components/TopicCard/Info.js
Normal file
|
@ -0,0 +1,105 @@
|
|||
/* global $ */
|
||||
|
||||
import React, { Component } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import { Link } from 'react-router'
|
||||
|
||||
class Info extends Component {
|
||||
constructor(props) {
|
||||
super(props)
|
||||
|
||||
this.state = {
|
||||
showInMaps: false,
|
||||
showMoreMaps: false,
|
||||
hoveringMapCount: false,
|
||||
hoveringSynapseCount: false
|
||||
}
|
||||
}
|
||||
|
||||
toggleShowMoreMaps = e => {
|
||||
e.stopPropagation()
|
||||
e.preventDefault()
|
||||
this.setState({ showMoreMaps: !this.state.showMoreMaps })
|
||||
}
|
||||
|
||||
updateState = (key, value) => () => {
|
||||
this.setState({ [key]: value })
|
||||
}
|
||||
|
||||
inMaps = (topic) => {
|
||||
const inmapsArray = topic.get('inmaps') || []
|
||||
const inmapsLinks = topic.get('inmapsLinks') || []
|
||||
|
||||
let firstFiveLinks = []
|
||||
let extraLinks = []
|
||||
for (let i = 0; i < inmapsArray.length; i++) {
|
||||
if (i < 5) {
|
||||
firstFiveLinks.push({ mapName: inmapsArray[i], mapId: inmapsLinks[i] })
|
||||
} else {
|
||||
extraLinks.push({ mapName: inmapsArray[i], mapId: inmapsLinks[i] })
|
||||
}
|
||||
}
|
||||
|
||||
let output = []
|
||||
|
||||
firstFiveLinks.forEach(obj => {
|
||||
output.push(<li key={obj.mapId}><Link to={`/maps/${obj.mapId}`}>{obj.mapName}</Link></li>)
|
||||
})
|
||||
|
||||
if (extraLinks.length > 0) {
|
||||
if (this.state.showMoreMaps) {
|
||||
extraLinks.forEach(obj => {
|
||||
output.push(<li key={obj.mapId} className="hideExtra extraText"><Link to={`/maps/${obj.mapId}`}>{obj.mapName}</Link></li>)
|
||||
})
|
||||
}
|
||||
const text = this.state.showMoreMaps ? 'See less...' : `See ${extraLinks.length} more...`
|
||||
output.push(<li key="showMore"><span className="showMore" onClick={this.toggleShowMoreMaps}>{text}</span></li>)
|
||||
}
|
||||
|
||||
return output
|
||||
}
|
||||
|
||||
render = () => {
|
||||
const { topic } = this.props
|
||||
|
||||
return (
|
||||
<div className="info">
|
||||
<div className="linkItem contributor">
|
||||
<a href={`/explore/mapper/${topic.get('user_id')}`} target="_blank">
|
||||
<img src={topic.get('user_image')} className="contributorIcon" width="32" height="32" />
|
||||
<div className="contributorName">{topic.get('user_name')}</div>
|
||||
</a>
|
||||
</div>
|
||||
<a href={`/topics/${topic.id}`}
|
||||
target="_blank"
|
||||
className="linkItem synapseCount"
|
||||
onMouseOver={this.updateState('hoveringSynapseCount', true)}
|
||||
onMouseOut={this.updateState('hoveringSynapseCount', false)}
|
||||
>
|
||||
<div className="synapseCountIcon"></div>
|
||||
{topic.get('synapse_count').toString()}
|
||||
{this.state.hoveringSynapseCount && <div className="tip">Click to see this topics synapses</div>}
|
||||
</a>
|
||||
<div className="linkItem mapCount"
|
||||
onMouseOver={this.updateState('hoveringMapCount', true)}
|
||||
onMouseOut={this.updateState('hoveringMapCount', false)}
|
||||
onClick={this.updateState('showInMaps', !this.state.showInMaps)}
|
||||
>
|
||||
<div className="mapCountIcon"></div>
|
||||
{topic.get('map_count').toString()}
|
||||
{!this.state.showInMaps && this.state.hoveringMapCount && (
|
||||
<div className="hoverTip">Click to see which maps topic appears on</div>
|
||||
)}
|
||||
{this.state.showInMaps && <div className="tip"><ul>{this.inMaps(topic)}</ul></div>}
|
||||
</div>
|
||||
<div className="clearfloat"></div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
Info.propTypes = {
|
||||
topic: PropTypes.object // backbone object
|
||||
}
|
||||
|
||||
export default Info
|
|
@ -2,22 +2,17 @@
|
|||
|
||||
import React, { Component } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import { Link } from 'react-router'
|
||||
|
||||
import MetacodeSelect from '../MetacodeSelect'
|
||||
import Permission from './Permission'
|
||||
import Follow from './Follow'
|
||||
|
||||
class Links extends Component {
|
||||
constructor(props) {
|
||||
super(props)
|
||||
|
||||
this.state = {
|
||||
showMetacodeTitle: false,
|
||||
showMetacodeSelect: false,
|
||||
showInMaps: false,
|
||||
showMoreMaps: false,
|
||||
hoveringMapCount: false,
|
||||
hoveringSynapseCount: false
|
||||
showMetacodeSelect: false
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -30,70 +25,23 @@ class Links extends Component {
|
|||
// which it currently does using backbone. If backbone comes out, make sure it still does
|
||||
}
|
||||
|
||||
toggleShowMoreMaps = e => {
|
||||
e.stopPropagation()
|
||||
e.preventDefault()
|
||||
this.setState({ showMoreMaps: !this.state.showMoreMaps })
|
||||
}
|
||||
|
||||
updateState = (key, value) => () => {
|
||||
this.setState({ [key]: value })
|
||||
}
|
||||
|
||||
inMaps = (topic) => {
|
||||
const inmapsArray = topic.get('inmaps') || []
|
||||
const inmapsLinks = topic.get('inmapsLinks') || []
|
||||
|
||||
let firstFiveLinks = []
|
||||
let extraLinks = []
|
||||
for (let i = 0; i < inmapsArray.length; i ++) {
|
||||
if (i < 5) {
|
||||
firstFiveLinks.push({ mapName: inmapsArray[i], mapId: inmapsLinks[i] })
|
||||
} else {
|
||||
extraLinks.push({ mapName: inmapsArray[i], mapId: inmapsLinks[i] })
|
||||
}
|
||||
}
|
||||
|
||||
let output = []
|
||||
|
||||
firstFiveLinks.forEach(obj => {
|
||||
output.push(<li key={obj.mapId}><Link to={`/maps/${obj.mapId}`}>{obj.mapName}</Link></li>)
|
||||
})
|
||||
|
||||
if (extraLinks.length > 0) {
|
||||
if (this.state.showMoreMaps) {
|
||||
extraLinks.forEach(obj => {
|
||||
output.push(<li key={obj.mapId} className="hideExtra extraText"><Link to={`/maps/${obj.mapId}`}>{obj.mapName}</Link></li>)
|
||||
})
|
||||
}
|
||||
const text = this.state.showMoreMaps ? 'See less...' : `See ${extraLinks.length} more...`
|
||||
output.push(<li key="showMore"><span className="showMore" onClick={this.toggleShowMoreMaps}>{text}</span></li>)
|
||||
}
|
||||
|
||||
return output
|
||||
}
|
||||
|
||||
handleMetacodeBarClick = () => {
|
||||
if (this.state.showMetacodeTitle) {
|
||||
this.setState({ showMetacodeSelect: !this.state.showMetacodeSelect })
|
||||
}
|
||||
this.setState({ showMetacodeSelect: !this.state.showMetacodeSelect })
|
||||
}
|
||||
|
||||
render = () => {
|
||||
const { topic, ActiveMapper } = this.props
|
||||
const { topic, onTopicFollow, ActiveMapper } = this.props
|
||||
const authorizedToEdit = topic.authorizeToEdit(ActiveMapper)
|
||||
const authorizedPermissionChange = topic.authorizePermissionChange(ActiveMapper)
|
||||
const metacode = topic.getMetacode()
|
||||
const wrappedTopicFollow = () => onTopicFollow(topic)
|
||||
const isFollowing = topic.isFollowedBy(ActiveMapper)
|
||||
|
||||
return (
|
||||
<div className="links">
|
||||
<div className="linkItem icon metacodeItem"
|
||||
style={{ zIndex: this.state.showMetacodeTitle ? 4 : 1 }}
|
||||
onMouseLeave={() => this.setState({ showMetacodeTitle: false, showMetacodeSelect: false })}
|
||||
onClick={() => authorizedToEdit && this.handleMetacodeBarClick()}
|
||||
>
|
||||
<div className={`metacodeTitle mbg${metacode.get('id')}`}
|
||||
style={{ display: this.state.showMetacodeTitle ? 'block' : 'none' }}
|
||||
<div className="linkItem icon metacodeItem">
|
||||
<div className={`metacodeTitle metacodeColor${metacode.get('id')}`}
|
||||
onClick={() => authorizedToEdit && this.handleMetacodeBarClick()}
|
||||
>
|
||||
{metacode.get('name')}
|
||||
<div className="expandMetacodeSelect"/>
|
||||
|
@ -101,7 +49,6 @@ class Links extends Component {
|
|||
<div className="metacodeImage"
|
||||
style={{backgroundImage: `url(${metacode.get('icon')})`}}
|
||||
title="click and drag to move card"
|
||||
onMouseEnter={() => this.setState({ showMetacodeTitle: true })}
|
||||
/>
|
||||
<div className="metacodeSelect"
|
||||
style={{ display: this.state.showMetacodeSelect ? 'block' : 'none' }}
|
||||
|
@ -109,32 +56,7 @@ class Links extends Component {
|
|||
<MetacodeSelect onMetacodeSelect={this.handleMetacodeSelect} metacodeSets={this.props.metacodeSets} />
|
||||
</div>
|
||||
</div>
|
||||
<div className="linkItem contributor">
|
||||
<a href={`/explore/mapper/${topic.get('user_id')}`} target="_blank"><img src={topic.get('user_image')} className="contributorIcon" width="32" height="32" /></a>
|
||||
<div className="contributorName">{topic.get('user_name')}</div>
|
||||
</div>
|
||||
<div className="linkItem mapCount"
|
||||
onMouseOver={this.updateState('hoveringMapCount', true)}
|
||||
onMouseOut={this.updateState('hoveringMapCount', false)}
|
||||
onClick={this.updateState('showInMaps', !this.state.showInMaps)}
|
||||
>
|
||||
<div className="mapCountIcon"></div>
|
||||
{topic.get('map_count').toString()}
|
||||
{!this.state.showInMaps && this.state.hoveringMapCount && (
|
||||
<div className="hoverTip">Click to see which maps topic appears on</div>
|
||||
)}
|
||||
{this.state.showInMaps && <div className="tip"><ul>{this.inMaps(topic)}</ul></div>}
|
||||
</div>
|
||||
<a href={`/topics/${topic.id}`}
|
||||
target="_blank"
|
||||
className="linkItem synapseCount"
|
||||
onMouseOver={this.updateState('hoveringSynapseCount', true)}
|
||||
onMouseOut={this.updateState('hoveringSynapseCount', false)}
|
||||
>
|
||||
<div className="synapseCountIcon"></div>
|
||||
{topic.get('synapse_count').toString()}
|
||||
{this.state.hoveringSynapseCount && <div className="tip">Click to see this topics synapses</div>}
|
||||
</a>
|
||||
<Follow ActiveMapper={ActiveMapper} isFollowing={isFollowing} onTopicFollow={wrappedTopicFollow} />
|
||||
<Permission
|
||||
permission={topic.get('permission')}
|
||||
authorizedToEdit={authorizedPermissionChange}
|
||||
|
@ -150,6 +72,7 @@ Links.propTypes = {
|
|||
topic: PropTypes.object, // backbone object
|
||||
ActiveMapper: PropTypes.object,
|
||||
updateTopic: PropTypes.func,
|
||||
onTopicFollow: PropTypes.func,
|
||||
metacodeSets: PropTypes.arrayOf(PropTypes.shape({
|
||||
name: PropTypes.string,
|
||||
metacodes: PropTypes.arrayOf(PropTypes.shape({
|
||||
|
|
|
@ -6,7 +6,7 @@ import Title from './Title'
|
|||
import Links from './Links'
|
||||
import Desc from './Desc'
|
||||
import Attachments from './Attachments'
|
||||
import Follow from './Follow'
|
||||
import Info from './Info'
|
||||
|
||||
class ReactTopicCard extends Component {
|
||||
render = () => {
|
||||
|
@ -16,10 +16,8 @@ class ReactTopicCard extends Component {
|
|||
if (!topic) return null
|
||||
|
||||
const wrappedUpdateTopic = obj => updateTopic(topic, obj)
|
||||
const wrappedTopicFollow = () => onTopicFollow(topic)
|
||||
|
||||
const authorizedToEdit = topic.authorizeToEdit(currentUser)
|
||||
const isFollowing = topic.isFollowedBy(currentUser)
|
||||
const hasAttachment = topic.get('link') && topic.get('link') !== ''
|
||||
|
||||
let classname = 'permission'
|
||||
|
@ -31,20 +29,21 @@ class ReactTopicCard extends Component {
|
|||
if (topic.authorizePermissionChange(currentUser)) classname += ' yourTopic'
|
||||
|
||||
return (
|
||||
<Draggable handle=".metacodeImage" defaultPosition={{x: 100, y: 100}}>
|
||||
<div className="showcard mapElement mapElementHidden">
|
||||
<Draggable handle='.metacodeImage' defaultPosition={{x: 100, y: 100}}>
|
||||
<div className='showcard mapElement mapElementHidden'>
|
||||
<div className={classname}>
|
||||
<div className={`CardOnGraph ${hasAttachment ? 'hasAttachment' : ''}`} id={`topic_${topic.id}`}>
|
||||
<Title name={topic.get('name')}
|
||||
authorizedToEdit={authorizedToEdit}
|
||||
onChange={wrappedUpdateTopic}
|
||||
/>
|
||||
<Links topic={topic}
|
||||
onTopicFollow={onTopicFollow}
|
||||
ActiveMapper={this.props.currentUser}
|
||||
updateTopic={wrappedUpdateTopic}
|
||||
metacodeSets={this.props.metacodeSets}
|
||||
redrawCanvas={this.props.redrawCanvas}
|
||||
/>
|
||||
<Title name={topic.get('name')}
|
||||
authorizedToEdit={authorizedToEdit}
|
||||
onChange={wrappedUpdateTopic}
|
||||
/>
|
||||
<Desc desc={topic.get('desc')}
|
||||
authorizedToEdit={authorizedToEdit}
|
||||
onChange={wrappedUpdateTopic}
|
||||
|
@ -53,8 +52,8 @@ class ReactTopicCard extends Component {
|
|||
authorizedToEdit={authorizedToEdit}
|
||||
updateTopic={wrappedUpdateTopic}
|
||||
/>
|
||||
<Follow isFollowing={isFollowing} onTopicFollow={wrappedTopicFollow} />
|
||||
<div className="clearfloat"></div>
|
||||
<Info topic={topic} />
|
||||
<div className='clearfloat' />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -48,7 +48,7 @@
|
|||
"react-draggable": "3.0.3",
|
||||
"react-dropzone": "4.1.2",
|
||||
"react-onclickoutside": "6.5.0",
|
||||
"react-router": "4.2.0",
|
||||
"react-router": "3.0.5",
|
||||
"redux": "3.7.2",
|
||||
"riek": "1.1.0",
|
||||
"simplewebrtc": "2.2.2",
|
||||
|
|
|
@ -47,7 +47,7 @@ module.exports = {
|
|||
'metamaps.bundle': './frontend/src/index.js'
|
||||
},
|
||||
output: {
|
||||
path: './app/assets/javascripts/webpacked',
|
||||
path: __dirname + '/app/assets/javascripts/webpacked',
|
||||
filename: '[name].js',
|
||||
devtoolModuleFilenameTemplate: '[absolute-resource-path]'
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue