Building CMS with Meteor
Vladimir Minkin
dqvsra
This talk about magic
GOALS
-
Works locally
-
Serve multiple screens
-
Preview content
-
Organize content
-
Render text to image
-
Month to build
Libraries:
-
Blaze + Semantic UI + ViewModel
-
ValueObjects + Comman + Q
-
Collection FS
-
Account UI + Iron Router
DESIGN
It's about:
- How
- When
- Where
- Usability
PRODUCT =
IDEA
+ DESIGN
+ REALIZATION
<template name="layout">
{{>loadfonts}}
{{>logo}}
{{>logout}}
{{>header}}
{{>menu}}
{{>content}}
</template>
ContentTypes = {
VIDEO : "video"
, IMAGE : "image"
, TEXT : "text"
, PACK : "pack"
};
MeteorMethods = {
ADD_SECTION : "meteor_method_add_section"
, ADD_CONTENT : "meteor_method_add_content"
, ADD_IMAGE : "meteor_method_add_image"
, ADD_TEXT_RENDER : "meteor_method_add_text_render"
, EDIT_CONTENT : "meteor_method_edit_content"
, EDIT_SECTION : "meteor_method_edit_section"
, GET_FIRST_SECTION : "meteor_method_get_first_section"
, REMOVE_SECTION : "meteor_method_remove_section"
, REMOVE_SUB_SECTIONS : "meteor_method_remove_sub_section"
, REMOVE_CONTENT : "meteor_method_remove_content"
, REMOVE_IMAGE : "meteor_method_remove_image"
, REMOVE_TEXT_RENDER : "meteor_method_remove_text_render"
, REPOSTION_CONTENT : "meteor_method_reposition_content"
, STORE_USER_SETTING : "meteor_method_store_user_settings"
, STORE_USER_NAV : "meteor_method_store_user_navigation"
, RENAME_SECTION : "meteor_methods_rename_section"
, SORT_SECTIONS : "meteor_methods_sort_sections"
, SELECT_SECTION : "meteor_methods_select_section"
, DESELECT_SECTION : "meteor_methods_deselect_section"
};
ModalCommands = {
SHOW_MODAL : "modal_command_show_modal"
, CREATE_SECTION : "modal_commands_show_create_section"
, REMOVE_SECTION : "modal_commands_show_remove_section"
, REMOVE_CONTENT : "modal_commands_show_remove_content"
};
CODE: Constants
CODE: Value Objects
Content = new Mongo.Collection("Content", {
transform: function (doc) { return new ContentVO(doc); }
});
Sections = new Mongo.Collection("Sections", {
transform: function (doc) { return new SectionVO(doc); }
});
ViewModel.share({
active: {
section: null
}
});
ViewModel
ViewModel is a view layer for Meteor.
You can think of it as Angular, Knockout, Aurelia, Vue, etc. but without the boilerplate code required to make those work.
https://viewmodel.org/
CODE: Components
CODE: Content binding
CODE: Select section
COMMAN
- Based on idea of Command Pattern
- Business logic extraction
- Can be "pure functions"
- Composition
Comman = (function(){
const comman = {};
const commands = {};
comman.handle = function(commandName, handlerFunction){
let commandHandler = {
handlerFunction: handlerFunction
};
commands[commandName] = commandHandler;
};
comman.execute = function(){
let args = Array.prototype.slice.call(arguments);
const name = args.shift();
const cmd = commands[name];
if (cmd) {
let defer = Q.defer();
cmd.handlerFunction.apply(defer, args);
return defer.promise;
} else {
throw new Error("No command with name:", name);
return null;
}
};
return comman;
})();
collection.insert(file, function (error, fileDoc) {
// console.log("ContentCommands.INSERT_MEDIA_FILE insert:", !error, collection);
if(fileDoc) {
let cursor = collection.find(fileDoc._id);
let progressStep = 1 / fileDoc.chunkSum;
let liveQuery = cursor.observe({
changed: function(newFileDoc, oldFileDoc) {
// console.log("ContentCommands.INSERT_MEDIA_FILE upload:", NProgress.status);
if(needToShowProgress) NProgress.inc(progressStep);
if (newFileDoc.isUploaded()) {
if(needToShowProgress) {
SuccessMessages.SAVE_COMPLETE(title);
NProgress.set(1);
}
liveQuery.stop();
liveQuery = null;
cursor = null;
// console.log("ContentCommands.INSERT_MEDIA_FILE complete");
that.resolve(newFileDoc);
}
}
});
} else {
if(needToShowProgress){
ErrorMessages.SAVE_FAILED(title);
NProgress.set(1);
}
that.reject(new Error("Problem when insert file"));
}
});
Images = new FS.Collection("SeverstalImages", {
stores: [new FS.Store.FileSystem("SeverstalImageStore", {path: pathToContent+"/images"})]
});
Iron Router
Accounts UI
<template name="login">
<div class="ui login middle aligned center aligned grid">
<div class="column">
{{> atForm state='signIn' hideSignUpLink='true' showForgotPasswordLink='true'}}
</div>
</div>
</template>
AccountsTemplates.removeField('password');
AccountsTemplates.removeField('email');
AccountsTemplates.addFields([
{
_id: "username",
type: "text",
required: true,
minLength: 5,
hasIcon: true,
iconClass: "user",
placeholder: "Имя вводить здесь",
errStr: 'Обязательно ввести имя пользователя',
displayName: "Имя пользователя"
},
...
]);
Ask questions
Live your love
THANK YOU!
Building CMS with Meteor
By Vladimir Cores Minkin
Building CMS with Meteor
- 606