Просмотр исходного кода

Feature: Add user-board view

pull/169/head
winkidney 5 лет назад
committed by Isaac Bythewood
Родитель
Сommit
e039ef7142
7 измененных файлов: 281 добавлений и 1 удалений
  1. Двоичные данные
      pinry-spa/src/assets/pinry-placeholder.jpg
  2. +227
    -0
      pinry-spa/src/components/Boards.vue
  3. +1
    -1
      pinry-spa/src/components/PHeader.vue
  4. +6
    -0
      pinry-spa/src/components/api.js
  5. +1
    -0
      pinry-spa/src/components/utils/fonts.scss
  6. +6
    -0
      pinry-spa/src/router/index.js
  7. +40
    -0
      pinry-spa/src/views/Boards4User.vue

Двоичные данные
pinry-spa/src/assets/pinry-placeholder.jpg Просмотреть файл

До После
Ширина: 240  |  Высота: 240  |  Размер: 3.1 KiB

+ 227
- 0
pinry-spa/src/components/Boards.vue Просмотреть файл

@@ -0,0 +1,227 @@
<template>
<div class="boards">
<section class="section">
<div id="boards-container" class="container" v-if="blocks">
<div
v-masonry="" transition-duration="0.3s"
item-selector=".grid-item"
column-width=".grid-sizer"
gutter=".gutter-sizer"
>
<template v-for="item in blocks">
<div v-bind:key="item.id"
v-masonry-tile
:class="item.class"
class="grid">
<div class="grid-sizer"></div>
<div class="gutter-sizer"></div>
<div class="board-card grid-item">
<router-link :to="{ name: 'board', params: { boardId: item.id } }">
<div class="card-image">
<img :src="item.preview_image_url"
@load="onPinImageLoaded(item.id)"
:style="item.style"
v-show="item.preview_image_url"
class="preview-image">
</div>
<div class="board-footer">
<p class="sub-title board-info">{{ item.name }}</p>

<p class="description">
<small>
Pins in board: <span class="num-pins">{{ item.total_pins }}</span>
</small>
</p>
</div>
</router-link>
</div>
</div>
</template>
</div>
</div>
<loadingSpinner v-bind:show="status.loading"></loadingSpinner>
<noMore v-bind:show="!status.hasNext"></noMore>
</section>
</div>
</template>

<script>
import API from './api';
import pinHandler from './utils/PinHandler';
import loadingSpinner from './loadingSpinner.vue';
import noMore from './noMore.vue';
import scroll from './utils/scroll';
import placeholder from '../assets/pinry-placeholder.jpg';

function createBoardItem(board) {
const defaultPreviewImage = placeholder;
const boardItem = {};
const pins4Board = board.pins_detail;
let previewImage = {
image: { thumbnail: { image: null, width: 240, height: 240 } },
};
if (pins4Board.length > 0) {
[previewImage] = pins4Board;
}
boardItem.id = board.id;
boardItem.name = board.name;
boardItem.total_pins = pins4Board.length;
if (previewImage.image.thumbnail.image !== null) {
boardItem.preview_image_url = pinHandler.escapeUrl(
previewImage.image.thumbnail.image,
);
} else {
boardItem.preview_image_url = defaultPreviewImage;
}
boardItem.style = {
width: `${previewImage.image.thumbnail.width}px`,
height: `${previewImage.image.thumbnail.height}px`,
};
boardItem.class = {};
return boardItem;
}

export default {
name: 'boards',
components: {
loadingSpinner,
noMore,
},
data() {
return {
blocks: [],
blocksMap: {},
status: {
loading: false,
hasNext: true,
offset: 0,
},
};
},
props: ['boardUsername'],
methods: {
onPinImageLoaded(itemId) {
this.blocksMap[itemId].class = {
'image-loaded': true,
};
},
registerScrollEvent() {
const self = this;
scroll.bindScroll2Bottom(
() => {
if (self.status.loading || !self.status.hasNext) {
return;
}
self.fetchMore();
},
);
},
buildBlocks(results) {
const blocks = [];
results.forEach(
(pin) => {
const item = createBoardItem(pin);
blocks.push(
item,
);
},
);
return blocks;
},
shouldFetchMore(created) {
if (!created) {
if (this.status.loading) {
return false;
}
if (!this.status.hasNext) {
return false;
}
}
return true;
},
fetchMore(created) {
if (!this.shouldFetchMore(created)) {
return;
}
this.status.loading = true;
const promise = API.fetchBoardForUser(this.boardUsername);
promise.then(
(resp) => {
const { results, next } = resp.data;
let newBlocks = this.buildBlocks(results);
newBlocks.forEach(
(item) => { this.blocksMap[item.id] = item; },
);
newBlocks = this.blocks.concat(newBlocks);
this.blocks = newBlocks;
this.status.offset = newBlocks.length;
this.status.hasNext = !(next === null);
this.status.loading = false;
},
() => { this.status.loading = false; },
);
},
},
created() {
this.registerScrollEvent();
this.fetchMore(true);
},
};
</script>

<style lang="scss" scoped>
/* grid */
.grid-sizer,
.grid-item { width: 240px; }
.grid-item {
margin-bottom: 15px;
}
.gutter-sizer {
width: 15px;
}

/* card */
$pin-footer-position-fix: -6px;
$avatar-width: 30px;
$avatar-height: 30px;
@import './utils/fonts';
@import './utils/loader.scss';

.board-card{
.preview-image {
max-height: 200px;
}
.card-image > img {
background-color: white;
border-radius: 3px 3px 0 0;
@include loader('../assets/loader.gif');
}
}
.board-footer {
position: relative;
top: $pin-footer-position-fix;
background-color: white;
border-radius: 0 0 3px 3px ;
box-shadow: 0 1px 0 #bbb;
font-weight: bold;
.description {
@include secondary-font;
padding-left: 10px;
padding-bottom: 5px;
overflow: hidden;
text-overflow: ellipsis;
}
.board-info {
padding: 10px;
color: $main-title-font-color;
}
.num-pins {
font-size: 0.8rem;
color: $main-title-font-color;
}
}

@import 'utils/grid-layout';
@include screen-grid-layout("#boards-container")

</style>

+ 1
- 1
pinry-spa/src/components/PHeader.vue Просмотреть файл

@@ -31,7 +31,7 @@
</a>
<div class="navbar-dropdown">
<router-link
to="/boards"
:to="{ name: 'boards4user', params: {username: user.meta.username} }"
class="navbar-item">
Boards
</router-link>


+ 6
- 0
pinry-spa/src/components/api.js Просмотреть файл

@@ -55,6 +55,11 @@ function fetchPinsForBoard(boardId) {
);
}

function fetchBoardForUser(username) {
const url = `${API_PREFIX}boards/?submitter__username=${username}`;
return axios.get(url);
}

const User = {
storageKey: 'pinry.user',
logIn(username, password) {
@@ -128,5 +133,6 @@ export default {
fetchPin,
fetchPins,
fetchPinsForBoard,
fetchBoardForUser,
User,
};

+ 1
- 0
pinry-spa/src/components/utils/fonts.scss Просмотреть файл

@@ -9,6 +9,7 @@
@mixin secondary-font-color-in-dark {
color: #878787;
}
$main-title-font-color: rgb(51, 51, 51);

// for pins component
@mixin pin-detail-font-size{


+ 6
- 0
pinry-spa/src/router/index.js Просмотреть файл

@@ -5,6 +5,7 @@ import Pins4Tag from '../views/Pins4Tag.vue';
import Pins4User from '../views/Pins4User.vue';
import Pins4Board from '../views/Pins4Board.vue';
import Pins4Id from '../views/Pins4Id.vue';
import Boards4User from '../views/Boards4User.vue';

Vue.use(VueRouter);

@@ -34,6 +35,11 @@ const routes = [
name: 'pin',
component: Pins4Id,
},
{
path: '/boards/users/:username',
name: 'boards4user',
component: Boards4User,
},
];

const router = new VueRouter({


+ 40
- 0
pinry-spa/src/views/Boards4User.vue Просмотреть файл

@@ -0,0 +1,40 @@
<template>
<div class="boards-for-user">
<PHeader></PHeader>
<Boards :boardUsername="username"></Boards>
</div>
</template>

<script>
import PHeader from '../components/PHeader.vue';
import Boards from '../components/Boards.vue';

export default {
name: 'Boards4User',
data() {
return {
username: null,
};
},
components: {
PHeader,
Boards,
},
created() {
this.initialize();
},
beforeRouteUpdate(to, from, next) {
this.initialize();
next();
},
methods: {
initialize() {
this.username = this.$route.params.username;
},
},
};
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped lang="scss">
</style>

Загрузка…
Отмена
Сохранить