refact about page

This commit is contained in:
yafeilee 2014-10-08 23:29:34 +08:00
parent 8bd6545c1b
commit 3042c7c08e
13 changed files with 873 additions and 52 deletions

View File

@ -12,6 +12,7 @@ gem 'uglifier', '>= 1.3.0'
gem 'jquery-rails' gem 'jquery-rails'
gem 'foundation-rails', '~> 5.2.1' gem 'foundation-rails', '~> 5.2.1'
gem 'foundation-icons-sass-rails' gem 'foundation-icons-sass-rails'
gem 'font-awesome-sass'
gem 'mongoid' gem 'mongoid'
gem 'mongoid-pagination' gem 'mongoid-pagination'

View File

@ -73,6 +73,8 @@ GEM
ffi (1.9.5) ffi (1.9.5)
figaro (1.0.0) figaro (1.0.0)
thor (~> 0.14) thor (~> 0.14)
font-awesome-sass (4.0.2)
sass-rails (>= 3.1.1)
formatador (0.2.5) formatador (0.2.5)
foundation-icons-sass-rails (3.0.0) foundation-icons-sass-rails (3.0.0)
railties (>= 3.1.1) railties (>= 3.1.1)
@ -285,6 +287,7 @@ DEPENDENCIES
database_cleaner database_cleaner
factory_girl_rails factory_girl_rails
figaro figaro
font-awesome-sass
foundation-icons-sass-rails foundation-icons-sass-rails
foundation-rails (~> 5.2.1) foundation-rails (~> 5.2.1)
guard guard

Binary file not shown.

After

Width:  |  Height:  |  Size: 108 KiB

View File

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="图形" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="1024px" height="1024px" viewBox="0 0 1024 1024" enable-background="new 0 0 1024 1024" xml:space="preserve">
<path fill="#219AB3" d="M926.917973 774.19392C959.65184 774.19392 986.19392 747.65184 986.19392 714.917973L986.19392-114.917973C986.19392-147.65184 959.65184-174.19392 926.917973-174.19392L97.082027-174.19392C64.34816-174.19392 37.80608-147.65184 37.80608-114.917973L37.80608 714.917973C37.80608 747.65184 64.34816 774.19392 97.082027 774.19392zM176.653653 635.80032 176.653653 559.321173 825.658027 559.321173 825.658027 635.80032zM217.719467 495.853653 217.719467 183.91936 273.524053 183.91936 341.292373 41.60384 157.259093 41.60384 157.259093-33.417813 842.949973-33.417813 842.949973 41.60384 654.226773 41.60384 722.899627 183.91936 783.67744 183.91936 783.67744 495.853653zM684.885333 419.108267 684.885333 258.012587 312.576 258.012587 312.576 419.108267zM570.770773 41.60384 426.653013 41.60384 359.621973 183.91936 639.443627 183.91936z" transform="translate(0, 812) scale(1, -1)"/>
</svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 86 KiB

589
app/assets/javascripts/angular-scroll.js vendored Normal file
View File

@ -0,0 +1,589 @@
/**
* x is a value between 0 and 1, indicating where in the animation you are.
*/
var duScrollDefaultEasing = function (x) {
'use strict';
if(x < 0.5) {
return Math.pow(x*2, 2)/2;
}
return 1-Math.pow((1-x)*2, 2)/2;
};
angular.module('duScroll', [
'duScroll.scrollspy',
'duScroll.smoothScroll',
'duScroll.scrollContainer',
'duScroll.spyContext',
'duScroll.scrollHelpers'
])
//Default animation duration for smoothScroll directive
.value('duScrollDuration', 350)
//Scrollspy debounce interval, set to 0 to disable
.value('duScrollSpyWait', 100)
//Wether or not multiple scrollspies can be active at once
.value('duScrollGreedy', false)
//Default offset for smoothScroll directive
.value('duScrollOffset', 0)
//Default easing function for scroll animation
.value('duScrollEasing', duScrollDefaultEasing);
angular.module('duScroll.scrollHelpers', ['duScroll.requestAnimation'])
.run(["$window", "$q", "cancelAnimation", "requestAnimation", "duScrollEasing", "duScrollDuration", "duScrollOffset", function($window, $q, cancelAnimation, requestAnimation, duScrollEasing, duScrollDuration, duScrollOffset) {
'use strict';
var proto = angular.element.prototype;
var isDocument = function(el) {
return (typeof HTMLDocument !== 'undefined' && el instanceof HTMLDocument) || (el.nodeType && el.nodeType === el.DOCUMENT_NODE);
};
var isElement = function(el) {
return (typeof HTMLElement !== 'undefined' && el instanceof HTMLElement) || (el.nodeType && el.nodeType === el.ELEMENT_NODE);
};
var unwrap = function(el) {
return isElement(el) || isDocument(el) ? el : el[0];
};
proto.scrollTo = function(left, top, duration, easing) {
var aliasFn;
if(angular.isElement(left)) {
aliasFn = this.scrollToElement;
} else if(duration) {
aliasFn = this.scrollToAnimated;
}
if(aliasFn) {
return aliasFn.apply(this, arguments);
}
var el = unwrap(this);
if(isDocument(el)) {
return $window.scrollTo(left, top);
}
el.scrollLeft = left;
el.scrollTop = top;
};
var scrollAnimation, deferred;
proto.scrollToAnimated = function(left, top, duration, easing) {
if(duration && !easing) {
easing = duScrollEasing;
}
var startLeft = this.scrollLeft(),
startTop = this.scrollTop(),
deltaLeft = Math.round(left - startLeft),
deltaTop = Math.round(top - startTop);
var startTime = null;
var el = this;
var cancelOnEvents = 'scroll mousedown mousewheel touchmove keydown';
var cancelScrollAnimation = function($event) {
if (!$event || $event.which > 0) {
el.unbind(cancelOnEvents, cancelScrollAnimation);
cancelAnimation(scrollAnimation);
deferred.reject();
scrollAnimation = null;
}
};
if(scrollAnimation) {
cancelScrollAnimation();
}
deferred = $q.defer();
if(!deltaLeft && !deltaTop) {
deferred.resolve();
return deferred.promise;
}
var animationStep = function(timestamp) {
if (startTime === null) {
startTime = timestamp;
}
var progress = timestamp - startTime;
var percent = (progress >= duration ? 1 : easing(progress/duration));
el.scrollTo(
startLeft + Math.ceil(deltaLeft * percent),
startTop + Math.ceil(deltaTop * percent)
);
if(percent < 1) {
scrollAnimation = requestAnimation(animationStep);
} else {
el.unbind(cancelOnEvents, cancelScrollAnimation);
scrollAnimation = null;
deferred.resolve();
}
};
//Fix random mobile safari bug when scrolling to top by hitting status bar
el.scrollTo(startLeft, startTop);
el.bind(cancelOnEvents, cancelScrollAnimation);
scrollAnimation = requestAnimation(animationStep);
return deferred.promise;
};
proto.scrollToElement = function(target, offset, duration, easing) {
var el = unwrap(this);
if(!angular.isNumber(offset) || isNaN(offset)) {
offset = duScrollOffset;
}
var top = this.scrollTop() + unwrap(target).getBoundingClientRect().top - offset;
if(isElement(el)) {
top -= el.getBoundingClientRect().top;
}
return this.scrollTo(0, top, duration, easing);
};
var overloaders = {
scrollLeft: function(value, duration, easing) {
if(angular.isNumber(value)) {
return this.scrollTo(value, this.scrollTop(), duration, easing);
}
var el = unwrap(this);
if(isDocument(el)) {
return $window.scrollX || document.documentElement.scrollLeft || document.body.scrollLeft;
}
return el.scrollLeft;
},
scrollTop: function(value, duration, easing) {
if(angular.isNumber(value)) {
return this.scrollTo(this.scrollTop(), value, duration, easing);
}
var el = unwrap(this);
if(isDocument(el)) {
return $window.scrollY || document.documentElement.scrollTop || document.body.scrollTop;
}
return el.scrollTop;
}
};
proto.scrollToElementAnimated = function(target, offset, duration, easing) {
return this.scrollToElement(target, offset, duration || duScrollDuration, easing);
};
proto.scrollTopAnimated = function(top, duration, easing) {
return this.scrollTop(top, duration || duScrollDuration, easing);
};
proto.scrollLeftAnimated = function(left, duration, easing) {
return this.scrollLeft(left, duration || duScrollDuration, easing);
};
//Add duration and easing functionality to existing jQuery getter/setters
var overloadScrollPos = function(superFn, overloadFn) {
return function(value, duration, easing) {
if(duration) {
return overloadFn.apply(this, arguments);
}
return superFn.apply(this, arguments);
};
};
for(var methodName in overloaders) {
proto[methodName] = (proto[methodName] ? overloadScrollPos(proto[methodName], overloaders[methodName]) : overloaders[methodName]);
}
}]);
//Adapted from https://gist.github.com/paulirish/1579671
angular.module('duScroll.polyfill', [])
.factory('polyfill', ["$window", function($window) {
'use strict';
var vendors = ['webkit', 'moz', 'o', 'ms'];
return function(fnName, fallback) {
if($window[fnName]) {
return $window[fnName];
}
var suffix = fnName.substr(0, 1).toUpperCase() + fnName.substr(1);
for(var key, i = 0; i < vendors.length; i++) {
key = vendors[i]+suffix;
if($window[key]) {
return $window[key];
}
}
return fallback;
};
}]);
angular.module('duScroll.requestAnimation', ['duScroll.polyfill'])
.factory('requestAnimation', ["polyfill", "$timeout", function(polyfill, $timeout) {
'use strict';
var lastTime = 0;
var fallback = function(callback, element) {
var currTime = new Date().getTime();
var timeToCall = Math.max(0, 16 - (currTime - lastTime));
var id = $timeout(function() { callback(currTime + timeToCall); },
timeToCall);
lastTime = currTime + timeToCall;
return id;
};
return polyfill('requestAnimationFrame', fallback);
}])
.factory('cancelAnimation', ["polyfill", "$timeout", function(polyfill, $timeout) {
'use strict';
var fallback = function(promise) {
$timeout.cancel(promise);
};
return polyfill('cancelAnimationFrame', fallback);
}]);
angular.module('duScroll.spyAPI', ['duScroll.scrollContainerAPI'])
.factory('spyAPI', ["$rootScope", "$timeout", "scrollContainerAPI", "duScrollGreedy", "duScrollSpyWait", function($rootScope, $timeout, scrollContainerAPI, duScrollGreedy, duScrollSpyWait) {
'use strict';
var createScrollHandler = function(context) {
var timer = false, queued = false;
var handler = function() {
queued = false;
var container = context.container,
containerEl = container[0],
containerOffset = 0;
if (typeof HTMLElement !== 'undefined' && containerEl instanceof HTMLElement || containerEl.nodeType && containerEl.nodeType === containerEl.ELEMENT_NODE) {
containerOffset = containerEl.getBoundingClientRect().top;
}
var i, currentlyActive, toBeActive, spies, spy, pos;
spies = context.spies;
currentlyActive = context.currentlyActive;
toBeActive = undefined;
for(i = 0; i < spies.length; i++) {
spy = spies[i];
pos = spy.getTargetPosition();
if (!pos) continue;
if(pos.top + spy.offset - containerOffset < 20 && (pos.top*-1 + containerOffset) < pos.height) {
if(!toBeActive || toBeActive.top < pos.top) {
toBeActive = {
top: pos.top,
spy: spy
};
}
}
}
if(toBeActive) {
toBeActive = toBeActive.spy;
}
if(currentlyActive === toBeActive || (duScrollGreedy && !toBeActive)) return;
if(currentlyActive) {
currentlyActive.$element.removeClass('active');
$rootScope.$broadcast('duScrollspy:becameInactive', currentlyActive.$element);
}
if(toBeActive) {
toBeActive.$element.addClass('active');
$rootScope.$broadcast('duScrollspy:becameActive', toBeActive.$element);
}
context.currentlyActive = toBeActive;
};
if(!duScrollSpyWait) {
return handler;
}
//Debounce for potential performance savings
return function() {
if(!timer) {
handler();
timer = $timeout(function() {
timer = false;
if(queued) {
handler();
}
}, duScrollSpyWait, false);
} else {
queued = true;
}
};
};
var contexts = {};
var createContext = function($scope) {
var id = $scope.$id;
var context = {
spies: []
};
context.handler = createScrollHandler(context);
contexts[id] = context;
$scope.$on('$destroy', function() {
destroyContext($scope);
});
return id;
};
var destroyContext = function($scope) {
var id = $scope.$id;
var context = contexts[id], container = context.container;
if(container) {
container.off('scroll', context.handler);
}
delete contexts[id];
};
var defaultContextId = createContext($rootScope);
var getContextForScope = function(scope) {
if(contexts[scope.$id]) {
return contexts[scope.$id];
}
if(scope.$parent) {
return getContextForScope(scope.$parent);
}
return contexts[defaultContextId];
};
var getContextForSpy = function(spy) {
var context, contextId, scope = spy.$element.scope();
if(scope) {
return getContextForScope(scope);
}
//No scope, most likely destroyed
for(contextId in contexts) {
context = contexts[contextId];
if(context.spies.indexOf(spy) !== -1) {
return context;
}
}
};
var isElementInDocument = function(element) {
while (element.parentNode) {
element = element.parentNode;
if (element === document) {
return true;
}
}
return false;
};
var addSpy = function(spy) {
var context = getContextForSpy(spy);
if (!context) return;
context.spies.push(spy);
if (!context.container || !isElementInDocument(context.container)) {
if(context.container) {
context.container.off('scroll', context.handler);
}
context.container = scrollContainerAPI.getContainer(spy.$element.scope());
context.container.on('scroll', context.handler).triggerHandler('scroll');
}
};
var removeSpy = function(spy) {
var context = getContextForSpy(spy);
if(spy === context.currentlyActive) {
context.currentlyActive = null;
}
var i = context.spies.indexOf(spy);
if(i !== -1) {
context.spies.splice(i, 1);
}
};
return {
addSpy: addSpy,
removeSpy: removeSpy,
createContext: createContext,
destroyContext: destroyContext,
getContextForScope: getContextForScope
};
}]);
angular.module('duScroll.scrollContainerAPI', [])
.factory('scrollContainerAPI', ["$document", function($document) {
'use strict';
var containers = {};
var setContainer = function(scope, element) {
var id = scope.$id;
containers[id] = element;
return id;
};
var getContainerId = function(scope) {
if(containers[scope.$id]) {
return scope.$id;
}
if(scope.$parent) {
return getContainerId(scope.$parent);
}
return;
};
var getContainer = function(scope) {
var id = getContainerId(scope);
return id ? containers[id] : $document;
};
var removeContainer = function(scope) {
var id = getContainerId(scope);
if(id) {
delete containers[id];
}
};
return {
getContainerId: getContainerId,
getContainer: getContainer,
setContainer: setContainer,
removeContainer: removeContainer
};
}]);
angular.module('duScroll.smoothScroll', ['duScroll.scrollHelpers', 'duScroll.scrollContainerAPI'])
.directive('duSmoothScroll', ["duScrollDuration", "duScrollOffset", "scrollContainerAPI", function(duScrollDuration, duScrollOffset, scrollContainerAPI) {
'use strict';
return {
link : function($scope, $element, $attr) {
$element.on('click', function(e) {
if(!$attr.href || $attr.href.indexOf('#') === -1) return;
var target = document.getElementById($attr.href.replace(/.*(?=#[^\s]+$)/, '').substring(1));
if(!target || !target.getBoundingClientRect) return;
if (e.stopPropagation) e.stopPropagation();
if (e.preventDefault) e.preventDefault();
var offset = $attr.offset ? parseInt($attr.offset, 10) : duScrollOffset;
var duration = $attr.duration ? parseInt($attr.duration, 10) : duScrollDuration;
var container = scrollContainerAPI.getContainer($scope);
container.scrollToElement(
angular.element(target),
isNaN(offset) ? 0 : offset,
isNaN(duration) ? 0 : duration
);
});
}
};
}]);
angular.module('duScroll.spyContext', ['duScroll.spyAPI'])
.directive('duSpyContext', ["spyAPI", function(spyAPI) {
'use strict';
return {
restrict: 'A',
scope: true,
compile: function compile(tElement, tAttrs, transclude) {
return {
pre: function preLink($scope, iElement, iAttrs, controller) {
spyAPI.createContext($scope);
}
};
}
};
}]);
angular.module('duScroll.scrollContainer', ['duScroll.scrollContainerAPI'])
.directive('duScrollContainer', ["scrollContainerAPI", function(scrollContainerAPI){
'use strict';
return {
restrict: 'A',
scope: true,
compile: function compile(tElement, tAttrs, transclude) {
return {
pre: function preLink($scope, iElement, iAttrs, controller) {
iAttrs.$observe('duScrollContainer', function(element) {
if(angular.isString(element)) {
element = document.getElementById(element);
}
element = (angular.isElement(element) ? angular.element(element) : iElement);
scrollContainerAPI.setContainer($scope, element);
$scope.$on('$destroy', function() {
scrollContainerAPI.removeContainer($scope);
});
});
}
};
}
};
}]);
angular.module('duScroll.scrollspy', ['duScroll.spyAPI'])
.directive('duScrollspy', ["spyAPI", "duScrollOffset", "$timeout", "$rootScope", function(spyAPI, duScrollOffset, $timeout, $rootScope) {
'use strict';
var Spy = function(targetElementOrId, $element, offset) {
if(angular.isElement(targetElementOrId)) {
this.target = targetElementOrId;
} else if(angular.isString(targetElementOrId)) {
this.targetId = targetElementOrId;
}
this.$element = $element;
this.offset = offset;
};
Spy.prototype.getTargetElement = function() {
if (!this.target && this.targetId) {
this.target = document.getElementById(this.targetId);
}
return this.target;
};
Spy.prototype.getTargetPosition = function() {
var target = this.getTargetElement();
if(target) {
return target.getBoundingClientRect();
}
};
Spy.prototype.flushTargetCache = function() {
if(this.targetId) {
this.target = undefined;
}
};
return {
link: function ($scope, $element, $attr) {
var href = $attr.ngHref || $attr.href;
var targetId;
if (href && href.indexOf('#') !== -1) {
targetId = href.replace(/.*(?=#[^\s]+$)/, '').substring(1);
} else if($attr.duScrollspy) {
targetId = $attr.duScrollspy;
}
if(!targetId) return;
// Run this in the next execution loop so that the scroll context has a chance
// to initialize
$timeout(function() {
var spy = new Spy(targetId, $element, -($attr.offset ? parseInt($attr.offset, 10) : duScrollOffset));
spyAPI.addSpy(spy);
$scope.$on('$destroy', function() {
spyAPI.removeSpy(spy);
});
$scope.$on('$locationChangeSuccess', spy.flushTargetCache.bind(spy));
$rootScope.$on('$stateChangeSuccess', spy.flushTargetCache.bind(spy));
}, 0, false);
}
};
}]);

View File

@ -2,10 +2,12 @@
#= require angular-cookies #= require angular-cookies
#= require angular-resource #= require angular-resource
#= require angular-sanitize #= require angular-sanitize
#= require angular-scroll
#= require_self #= require_self
#= require_tree ./angularjs #= require_tree ./angularjs
@app = angular.module('app', ['ngCookies', 'ngSanitize']) @app = angular.module('app', ['ngCookies', 'ngSanitize', 'duScroll'])
@app.value('duScrollOffset', 30)
@app.config(["$httpProvider", (provider) -> @app.config(["$httpProvider", (provider) ->
provider.defaults.headers.common['X-CSRF-Token'] = $('meta[name=csrf-token]').attr('content') provider.defaults.headers.common['X-CSRF-Token'] = $('meta[name=csrf-token]').attr('content')

View File

@ -0,0 +1,6 @@
@app.controller 'AboutScrollController', [ '$scope', '$document', ($scope, $document)->
about_id = angular.element(document.getElementById('about'))
$scope.to_about = ()->
$document.scrollToElementAnimated(about_id)
]

View File

@ -3,6 +3,7 @@
//= require foundation/foundation //= require foundation/foundation
//= require foundation/foundation.topbar //= require foundation/foundation.topbar
//= require foundation/foundation.offcanvas //= require foundation/foundation.offcanvas
//= require foundation/foundation.magellan
//= require angularjs //= require angularjs
//= require 'jquery.html5-fileupload' //= require 'jquery.html5-fileupload'
//= require_tree . //= require_tree .

View File

@ -20,3 +20,151 @@
} }
} }
} }
.about-page {
.top-bar-wrapper {
background: 0 0;
.top-bar {
background: 0 0;
padding: 1.5rem 0;
}
.top-bar-section ul{
li, li a {
background: 0 0;
}
li a:hover {
background: #666;
}
}
}
p {
font-size: 1.275rem;
}
.intro {
//background-color: #7A7A7A;
background: image-url('intro-bg.jpg') no-repeat bottom center scroll;
background-size: cover;
height: 100%;
width: 100%;
display: table;
.intro-heading {
display: table-cell;
vertical-align: middle;
text-align: center;
.heading, .sub-heading {
color: #fff;
}
.sub-heading {
margin-top: 2rem;
p {
line-height: 2;
}
}
.circle {
color: #fff;
width: 4rem;
height: 4rem;
font-size: 3rem;
border: 2px solid #eee;
display: inline-block;
border-radius: 50%;
padding: 0.5rem 0;
margin-top: 2rem;
&:hover {
opacity: 0.7;
}
}
}
}
#about {
background-color: #000;
color: #eee;
padding: 10rem 0;
h1, h2 {
color: #eee;
text-align: center;
margin-bottom: 2rem;
}
}
#work {
background: image-url('download-bg.jpg') no-repeat bottom center scroll;
background-size: cover;
padding: 10rem 0;
h1, h2 {
color: #eee;
text-align: center;
margin-bottom: 2rem;
}
p {
color: #eee;
text-align: center;
}
}
#contact {
background: #000;
background-size: cover;
padding: 10rem 0;
padding-bottom: 20rem;
h1, h2 {
color: #eee;
text-align: center;
margin-bottom: 2rem;
}
p {
color: #eee;
text-align: center;
}
.mail_to {
margin-bottom: 3rem;
margin-top: -1rem;
}
.contact-ul {
text-align: center;
li {
display: inline-block;
}
li a {
display: inline-block;
padding: 0.5rem 2rem;
border: 1px solid #219AB3;
border-radius: 0.5rem;
color: #219AB3;
margin: 0 1rem;
transition: all .3s ease-in-out;
&:hover {
outline: 0;
color: #000;
background-color: #219ab3;
}
i {
margin-right: 0.5rem;
font-size: 1.1rem;
}
i.douban {
font-style: normal;
font-size: 95%;
vertical-align: baseline;
}
}
}
}
}

View File

@ -1190,3 +1190,4 @@ $base-font-size: 100%;
@import 'foundation'; @import 'foundation';
@import 'foundation-icons'; @import 'foundation-icons';
@import 'font-awesome';

View File

@ -1,5 +1,67 @@
- content_for(:title) do - content_for(:title) do
| 关于我 | 关于我
.row - content_for(:main) do
.small-12.large-9.large-centered.columns.self-introduce /! 导航
= render 'common/aboutme' .about-page ng-app='app' ng-controller='AboutScrollController'
.top-bar-wrapper.contain-to-grid.fixed
.row
.small-12.columns
nav.top-bar data-topbar='' role='navigation'
ul.title-area
li.name
h1
a href='/' WinDy's Blog
section.top-bar-section
ul.right
li
a href='#about' du-smooth-scroll='' du-scrollspy='' 关于
li
a href='#work' du-smooth-scroll='' du-scrollspy='' 作品
li
a href='#contact' du-smooth-scroll='' du-scrollspy='' 联系
header.intro
.intro-heading
.row
.small-12.columns
h1.heading 李亚飞
.sub-heading
p
| 懒, 是人类进步的动力
br
| 所谓技术, 就是让你的生活越来越懒
a.circle href='#about' du-smooth-scroll=''
i.fa.fa-angle-double-down
section#about
.row
.small-12.large-9.large-centered.columns
h1.title 关于我
p Grayscale is a free Bootstrap 3 theme created by Start Bootstrap. It can be yours right now, simply download the template on the preview page. The theme is open source, and you can use it for any purpose, personal or commercial.
p Grayscale is a free Bootstrap 3 theme created by Start Bootstrap. It can be yours right now, simply download the template on the preview page. The theme is open source, and you can use it for any purpose, personal or commercial.
p Grayscale is a free Bootstrap 3 theme created by Start Bootstrap. It can be yours right now, simply download the template on the preview page. The theme is open source, and you can use it for any purpose, personal or commercial.
section#work
.row
.small-12.large-9.large-centered.columns
h1.title 作品
p Grayscale is a free Bootstrap 3 theme created by Start Bootstrap. It can be yours right now, simply download the template on the preview page. The theme is open source, and you can use it for any purpose, personal or commercial.
p Grayscale is a free Bootstrap 3 theme created by Start Bootstrap. It can be yours right now, simply download the template on the preview page. The theme is open source, and you can use it for any purpose, personal or commercial.
p Grayscale is a free Bootstrap 3 theme created by Start Bootstrap. It can be yours right now, simply download the template on the preview page. The theme is open source, and you can use it for any purpose, personal or commercial.
section#contact
.row
.small-12.large-9.large-centered.columns
h1.title 联系我
p.mail_to
= mail_to 'lyfi2003@gmail.com'
ul.contact-ul
li
a href='https://github.com/windy' target='_blank'
i.fa.fa-github
| Github
li
a href='http://www.douban.com/people/41759170/' target='_blank'
i.douban
| 豆
| Douban
li
a href='http://www.linkedin.com/pub/yafei-lee/77/3b/505' target='_blank'
i.fa.fa-linkedin-square
| LinkedIn

View File

@ -13,53 +13,56 @@ html
/ 增加 favico 图标 / 增加 favico 图标
link href="/favicon.png" type='image/png' rel="icon" link href="/favicon.png" type='image/png' rel="icon"
body body
.off-canvas-wrap data-offcanvas='' - if content_for?(:main)
.inner-wrap = yield(:main)
nav.tab-bar - else
section.left-small .off-canvas-wrap data-offcanvas=''
a.left-off-canvas-toggle.menu-icon href="#" .inner-wrap
span nav.tab-bar
h1.title.middle-text section.left-small
= link_to ENV['SITE_NAME'], root_path a.left-off-canvas-toggle.menu-icon href="#"
aslide.left-off-canvas-menu span
ul.off-canvas-list h1.title.middle-text
li = link_to ENV['SITE_NAME'], root_path
label Menu aslide.left-off-canvas-menu
li ul.off-canvas-list
= link_to root_path do li
i.fi-home label Menu
| 首页 li
li = link_to root_path do
= link_to '/tech' do i.fi-home
i.fi-social-evernote | 首页
| 技术 li
li = link_to '/tech' do
= link_to '/life' do i.fi-social-evernote
i.fi-torsos-male-female | 技术
| 生活 li
li = link_to '/life' do
= link_to '/creator' do i.fi-torsos-male-female
i.fi-lightbulb | 生活
| 创业 li
li = link_to '/creator' do
label Archive i.fi-lightbulb
li | 创业
= link_to archives_path do li
i.fi-align-justify label Archive
| 时间线 li
li = link_to archives_path do
label About i.fi-align-justify
= link_to about_path do | 时间线
i.fi-torso li
| 关于我 label About
section.main-section ng-app="app" = link_to about_path do
- flash.each do |name, msg| i.fi-torso
- if msg.is_a?(String) | 关于我
div class=("alert-box #{name == :notice ? "success" : "alert"}") data-alert="" section.main-section ng-app="app"
= content_tag :div, msg - flash.each do |name, msg|
a.close href="#" &times; - if msg.is_a?(String)
= yield div class=("alert-box #{name == :notice ? "success" : "alert"}") data-alert=""
= render "layouts/footer" = content_tag :div, msg
a.exit-off-canvas a.close href="#" &times;
= yield
= render "layouts/footer"
a.exit-off-canvas
= render 'layouts/google_analytics' = render 'layouts/google_analytics'