mirror of
https://github.com/LaCasemate/fab-manager.git
synced 2025-01-17 06:52:27 +01:00
react coponent: plan-card + extracted scss from stylesheet.rb into themes/
This commit is contained in:
parent
f5687f1120
commit
4f877ab05d
3
Gemfile
3
Gemfile
@ -136,3 +136,6 @@ gem 'repost'
|
||||
gem 'icalendar'
|
||||
|
||||
gem 'tzinfo-data'
|
||||
|
||||
# compilation of dynamic stylesheets (home page & theme)
|
||||
gem 'sassc'
|
||||
|
@ -336,6 +336,8 @@ GEM
|
||||
rubyzip (>= 1.3.0)
|
||||
rubyzip (1.3.0)
|
||||
safe_yaml (1.0.5)
|
||||
sassc (2.2.1)
|
||||
ffi (~> 1.9)
|
||||
seed_dump (3.3.1)
|
||||
activerecord (>= 4)
|
||||
activesupport (>= 4)
|
||||
@ -476,6 +478,7 @@ DEPENDENCIES
|
||||
rubocop (~> 0.61.1)
|
||||
rubyXL
|
||||
rubyzip (>= 1.3.0)
|
||||
sassc
|
||||
seed_dump
|
||||
sha3
|
||||
sidekiq (>= 6.0.7)
|
||||
|
@ -5,19 +5,25 @@
|
||||
import React from 'react';
|
||||
import { react2angular } from 'react2angular';
|
||||
import { IFilterService } from 'angular';
|
||||
import moment from "moment";
|
||||
import moment from 'moment';
|
||||
import _ from 'lodash'
|
||||
import { IApplication } from '../models/application';
|
||||
import { Plan } from '../models/plan';
|
||||
import { User, UserRole } from '../models/user';
|
||||
|
||||
declare var Application: IApplication;
|
||||
|
||||
interface PlanCardProps {
|
||||
plan: Plan,
|
||||
_t: (key: string, interpolation: object) => string,
|
||||
user: User,
|
||||
operator: User,
|
||||
isSelected: boolean,
|
||||
onSelectPlan: (plan: Plan) => void,
|
||||
_t: (key: string, interpolation?: object) => Promise<string>,
|
||||
$filter: IFilterService
|
||||
}
|
||||
|
||||
const PlanCard: React.FC<PlanCardProps> = ({ plan, _t, $filter }) => {
|
||||
const PlanCard: React.FC<PlanCardProps> = ({ plan, user, operator, onSelectPlan, isSelected, _t, $filter }) => {
|
||||
/**
|
||||
* Return the formatted localized amount of the given plan (eg. 20.5 => "20,50 €")
|
||||
*/
|
||||
@ -30,6 +36,30 @@ const PlanCard: React.FC<PlanCardProps> = ({ plan, _t, $filter }) => {
|
||||
const duration = (): string => {
|
||||
return moment.duration(plan.interval_count, plan.interval).humanize();
|
||||
}
|
||||
/**
|
||||
* Check if the user can subscribe to the current plan, for himself
|
||||
*/
|
||||
const canSubscribeForMe = (): boolean => {
|
||||
return operator?.role === UserRole.Member || (operator?.role === UserRole.Manager && user?.id === operator?.id)
|
||||
}
|
||||
/**
|
||||
* Check if the user can subscribe to the current plan, for someone else
|
||||
*/
|
||||
const canSubscribeForOther = (): boolean => {
|
||||
return operator?.role === UserRole.Admin || (operator?.role === UserRole.Manager && user?.id !== operator?.id)
|
||||
}
|
||||
/**
|
||||
* Check it the user has subscribed to this plan or not
|
||||
*/
|
||||
const hasSubscribedToThisPlan = (): boolean => {
|
||||
return user?.subscription?.plan?.id === plan.id;
|
||||
}
|
||||
/**
|
||||
* Callback triggered when the user select the plan
|
||||
*/
|
||||
const handleSelectPlan = (): void => {
|
||||
onSelectPlan(plan);
|
||||
}
|
||||
return (
|
||||
<div>
|
||||
<h3 className="title">{plan.base_name}</h3>
|
||||
@ -41,8 +71,26 @@ const PlanCard: React.FC<PlanCardProps> = ({ plan, _t, $filter }) => {
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{canSubscribeForMe() && <div className="cta-button">
|
||||
{!hasSubscribedToThisPlan() && <button className={`subscribe-button ${isSelected ? 'selected-card' : ''}`}
|
||||
onClick={handleSelectPlan}
|
||||
disabled={!_.isNil(user.subscription)}>
|
||||
{user && <span>{_t('app.public.plans.i_choose_that_plan')}</span>}
|
||||
{!user && <span>{_t('app.public.plans.i_subscribe_online')}</span>}
|
||||
</button>}
|
||||
{hasSubscribedToThisPlan() && <button className="subscribe-button" disabled>
|
||||
{ _t('app.public.plans.i_already_subscribed') }
|
||||
</button>}
|
||||
</div>}
|
||||
{canSubscribeForOther() && <div className="cta-button">
|
||||
<button className={`subscribe-button ${isSelected ? 'selected-card' : ''}`}
|
||||
onClick={handleSelectPlan}
|
||||
disabled={_.isNil(user)}>
|
||||
<span>{ _t('app.public.plans.i_choose_that_plan') }</span>
|
||||
</button>
|
||||
</div>}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
Application.Components.component('planCard', react2angular(PlanCard, ['plan'], ['_t', '$filter']));
|
||||
Application.Components.component('planCard', react2angular(PlanCard, ['plan', 'user', 'operator', 'onSelectPlan', 'isSelected'], ['_t', '$filter']));
|
||||
|
@ -72,16 +72,27 @@ Application.Controllers.controller('PlansIndexController', ['$scope', '$rootScop
|
||||
* @param plan {Object} The plan to subscribe to
|
||||
*/
|
||||
$scope.selectPlan = function (plan) {
|
||||
if ($scope.isAuthenticated()) {
|
||||
if ($scope.selectedPlan !== plan) {
|
||||
$scope.selectedPlan = plan;
|
||||
updateCartPrice();
|
||||
setTimeout(() => {
|
||||
if ($scope.isAuthenticated()) {
|
||||
if ($scope.selectedPlan !== plan) {
|
||||
$scope.selectedPlan = plan;
|
||||
updateCartPrice();
|
||||
} else {
|
||||
$scope.selectedPlan = null;
|
||||
}
|
||||
} else {
|
||||
$scope.selectedPlan = null;
|
||||
$scope.login();
|
||||
}
|
||||
} else {
|
||||
$scope.login();
|
||||
}
|
||||
$scope.$apply();
|
||||
}, 50);
|
||||
};
|
||||
|
||||
/**
|
||||
* Check if the provided plan is currently selected
|
||||
* @param plan {Object} Resource plan
|
||||
*/
|
||||
$scope.isSelected = function (plan) {
|
||||
return $scope.selectedPlan === plan;
|
||||
};
|
||||
|
||||
/**
|
||||
|
85
app/frontend/src/javascript/models/user.ts
Normal file
85
app/frontend/src/javascript/models/user.ts
Normal file
@ -0,0 +1,85 @@
|
||||
import { Plan } from './plan';
|
||||
|
||||
|
||||
export enum UserRole {
|
||||
Member = 'member',
|
||||
Manager = 'manager',
|
||||
Admin = 'admin'
|
||||
}
|
||||
|
||||
export interface User {
|
||||
id: number,
|
||||
username: string,
|
||||
email: string,
|
||||
group_id: number,
|
||||
role: UserRole
|
||||
name: string,
|
||||
need_completion: boolean,
|
||||
profile: {
|
||||
id: number,
|
||||
first_name: string,
|
||||
last_name: string,
|
||||
interest: string,
|
||||
software_mastered: string,
|
||||
phone: string,
|
||||
website: string,
|
||||
job: string,
|
||||
tours: Array<string>,
|
||||
facebook: string,
|
||||
twitter: string,
|
||||
google_plus: string,
|
||||
viadeo: string,
|
||||
linkedin: string,
|
||||
instagram: string,
|
||||
youtube: string,
|
||||
vimeo: string,
|
||||
dailymotion: string,
|
||||
github: string,
|
||||
echosciences: string,
|
||||
pinterest: string,
|
||||
lastfm: string,
|
||||
flickr: string,
|
||||
user_avatar: {
|
||||
id: number,
|
||||
attachment_url: string
|
||||
}
|
||||
},
|
||||
invoicing_profile: {
|
||||
id: number,
|
||||
address: {
|
||||
id: number,
|
||||
address: string
|
||||
},
|
||||
organization: {
|
||||
id: number,
|
||||
name: string,
|
||||
address: {
|
||||
id: number,
|
||||
address: string
|
||||
}
|
||||
}
|
||||
},
|
||||
statistic_profile: {
|
||||
id: number,
|
||||
gender: string,
|
||||
birthday: Date
|
||||
},
|
||||
subscribed_plan: Plan,
|
||||
subscription: {
|
||||
id: number,
|
||||
expired_at: Date,
|
||||
canceled_at: Date,
|
||||
stripe: boolean,
|
||||
plan: {
|
||||
id: number,
|
||||
base_name: string,
|
||||
name: string,
|
||||
interval: string,
|
||||
interval_count: number,
|
||||
amount: number
|
||||
}
|
||||
},
|
||||
training_credits: Array<number>,
|
||||
machine_credits: Array<{machine_id: number, hours_used: number}>,
|
||||
last_sign_in_at: Date
|
||||
}
|
@ -333,7 +333,10 @@
|
||||
.cta-button {
|
||||
margin: 20px 0;
|
||||
|
||||
.btn {
|
||||
.subscribe-button {
|
||||
@extend .btn;
|
||||
@extend .rounded;
|
||||
|
||||
outline: 0;
|
||||
font-weight: 600;
|
||||
font-size: rem-calc(16);
|
||||
|
@ -31,25 +31,12 @@
|
||||
ng-class="{'col-md-12 col-lg-12 b-r':(plansGroup.plans.filter(filterDisabledPlans).length % 2 == 1 && key == plansGroup.plans.filter(filterDisabledPlans).length-1)}"
|
||||
ng-repeat="(key, plan) in plansGroup.plans.filter(filterDisabledPlans) | orderBy: '-ui_weight'">
|
||||
|
||||
<plan-card plan="plan"></plan-card>
|
||||
|
||||
<div class="cta-button" ng-if="isAuthorized('member') || (isAuthorized('manager') && ctrl.member.id === currentUser.id)">
|
||||
<button class="btn btn-default rounded" ng-click="selectPlan(plan)" ng-if="ctrl.member.subscribed_plan.id != plan.id" ng-disabled="ctrl.member.subscribed_plan" ng-class="{ 'bg-yellow': selectedPlan==plan }">
|
||||
<span ng-if="ctrl.member" translate>{{ 'app.public.plans.i_choose_that_plan' }}</span>
|
||||
<span ng-if="!ctrl.member" translate>{{ 'app.public.plans.i_subscribe_online' }}</span>
|
||||
</button>
|
||||
|
||||
<button class="btn btn-warning bg-yellow rounded" ng-if="ctrl.member.subscribed_plan.id == plan.id" ng-disabled="ctrl.member.subscribed_plan.id == plan.id" translate>
|
||||
{{ 'app.public.plans.i_already_subscribed' }}
|
||||
</button>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="cta-button" ng-if="isAuthorized('admin') || (isAuthorized('manager') && ctrl.member.id != currentUser.id)">
|
||||
<button class="btn btn-default rounded" ng-click="selectPlan(plan)" ng-class="{ 'bg-yellow': selectedPlan==plan }" ng-disabled="!ctrl.member">
|
||||
<span translate>{{ 'app.public.plans.i_choose_that_plan' }}</span>
|
||||
</button>
|
||||
</div>
|
||||
<plan-card plan="plan"
|
||||
user="ctrl.member"
|
||||
operator="currentUser"
|
||||
on-select-plan="selectPlan"
|
||||
is-selected="isSelected(plan)">
|
||||
</plan-card>
|
||||
|
||||
<br ng-show="!plan.plan_file_url"> <!-- TODO Refacto with CSS -->
|
||||
<a ng-href="{{ plan.plan_file_url }}" ng-show="plan.plan_file_url" target="_blank" translate>{{ 'app.public.plans.more_information' }}</a>
|
||||
|
@ -15,7 +15,7 @@ class Stylesheet < ApplicationRecord
|
||||
|
||||
def rebuild!
|
||||
if Stylesheet.primary && Stylesheet.secondary && name == 'theme'
|
||||
update(contents: Stylesheet.css)
|
||||
update(contents: Stylesheet.theme_css)
|
||||
elsif name == 'home_page'
|
||||
update(contents: Stylesheet.home_page_css)
|
||||
end
|
||||
@ -29,7 +29,7 @@ class Stylesheet < ApplicationRecord
|
||||
if Stylesheet.theme
|
||||
Stylesheet.theme.rebuild!
|
||||
else
|
||||
Stylesheet.create!(contents: Stylesheet.css, name: 'theme')
|
||||
Stylesheet.create!(contents: Stylesheet.theme_css, name: 'theme')
|
||||
end
|
||||
end
|
||||
|
||||
@ -77,56 +77,10 @@ class Stylesheet < ApplicationRecord
|
||||
Stylesheet.secondary.paint.brightness <= BRIGHTNESS_LOW_LIMIT ? 'white' : 'black'
|
||||
end
|
||||
|
||||
def self.css # rubocop:disable Metrics/AbcSize
|
||||
<<~CSS
|
||||
.bg-red { background-color: #{Stylesheet.primary}; }
|
||||
.bg-red-dark { background-color: #{Stylesheet.primary}; }
|
||||
#nav .nav { background-color: #{Stylesheet.primary}; }
|
||||
#nav .nav > li > a { color: #{Stylesheet.primary_text_color}; }
|
||||
#nav .nav > li > a:hover, #nav .nav > li > a:focus { background-color: #{Stylesheet.primary_light}; color: #{Stylesheet.primary_text_color}; }
|
||||
#nav .nav > li > a.active { border-left: 3px solid #{Stylesheet.primary_dark}; background-color: #{Stylesheet.primary_light}; color: #{Stylesheet.primary_text_color}; }
|
||||
.nav-primary ul.nav > li.menu-spacer { background: linear-gradient(45deg, #{Stylesheet.primary_decoration_color}, transparent); }
|
||||
.nav-primary .text-bordeau { color: #{Stylesheet.primary_decoration_color}; }
|
||||
.btn-theme { background-color: #{Stylesheet.primary}; color: #{Stylesheet.primary_text_color}; }
|
||||
.btn-theme:active, .btn-theme:hover { background-color: #{Stylesheet.primary_dark}; color: #{Stylesheet.primary_text_color}; }
|
||||
.label-theme { background-color: #{Stylesheet.primary}; color: #{Stylesheet.primary_text_color}; }
|
||||
.btn-link { color: #{Stylesheet.primary} !important; }
|
||||
.btn-link:hover { color: #{Stylesheet.primary_dark} !important; }
|
||||
a { color: #{Stylesheet.primary}; }
|
||||
.about-page-link a.about-link, .user-profile-nav b.caret { color: #{Stylesheet.primary}; }
|
||||
.app-generator a, .home-events h4 a, a.reinit-filters, .pricing-panel a, .calendar-url a, .article a, a.project-author, a.dsq-brlink, .alert a, .about-fablab a, a.collected-infos { color: #{Stylesheet.primary}; }
|
||||
.app-generator a:hover, .home-events h4 a:hover, a.reinit-filters:hover, .pricing-panel a:hover, .calendar-url a:hover, .article a:hover, a.project-author:hover, a.dsq-brlink:hover, .widget .widget-content a:hover, .alert a:hover, .about-fablab a:hover, a.collected-infos:hover { color: #{Stylesheet.primary_dark}; }
|
||||
.btn.btn-default.reserve-button, .btn.btn-default.show-button, .btn.btn-default.red { color: #{Stylesheet.primary} !important; }
|
||||
.nav.nav-tabs .uib-tab.nav-item:not(.active) a { color: #{Stylesheet.primary}; }
|
||||
.article h2, .article h3, .article h5 { color: #{Stylesheet.primary} !important; }
|
||||
table.table thead tr th a, table.table tbody tr td a:not(.btn) { color: #{Stylesheet.primary}; }
|
||||
table.table thead tr th a:hover, table.table tbody tr td a:not(.btn):hover { color: #{Stylesheet.primary_dark}; }
|
||||
a:hover, a:focus { color: #{Stylesheet.primary_dark}; }
|
||||
h2, h3, h3.red, h5 { color: #{Stylesheet.primary} !important; }
|
||||
h5:after { background-color: #{Stylesheet.primary}; }
|
||||
.bg-yellow { background-color: #{Stylesheet.secondary} !important; color: #{Stylesheet.secondary_text_color}; }
|
||||
.event:hover { background-color: #{Stylesheet.primary}; color: #{Stylesheet.secondary_text_color}; }
|
||||
.widget h3 { color: #{Stylesheet.primary}; }
|
||||
.modal-header h1, .custom-invoice .modal-header h1 { color: #{Stylesheet.primary}; }
|
||||
.block-link:hover, .fc-toolbar .fc-button:hover, .fc-toolbar .fc-button:active, .fc-toolbar .fc-button.fc-state-active { background-color: #{Stylesheet.secondary}; color: #{Stylesheet.secondary_text_color} !important; }
|
||||
.block-link:hover .user-name { color: #{Stylesheet.secondary_text_color} !important; }
|
||||
.carousel-control:hover, .carousel-control:focus, .carousel-caption .title a:hover { color: #{Stylesheet.secondary}; }
|
||||
.well.well-warning { border-color: #{Stylesheet.secondary}; background-color: #{Stylesheet.secondary}; color: #{Stylesheet.secondary_text_color}; }
|
||||
.text-yellow { color: #{Stylesheet.secondary} !important; }
|
||||
.red { color: #{Stylesheet.primary} !important; }
|
||||
.btn-warning, .editable-buttons button[type=submit].btn-primary { background-color: #{Stylesheet.secondary} !important; border-color: #{Stylesheet.secondary} !important; color: #{Stylesheet.secondary_text_color}; }
|
||||
.btn-warning:hover, .editable-buttons button[type=submit].btn-primary:hover, .btn-warning:focus, .editable-buttons button[type=submit].btn-primary:focus, .btn-warning.focus, .editable-buttons button.focus[type=submit].btn-primary, .btn-warning:active, .editable-buttons button[type=submit].btn-primary:active, .btn-warning.active, .editable-buttons button.active[type=submit].btn-primary, .open > .btn-warning.dropdown-toggle, .editable-buttons .open > button.dropdown-toggle[type=submit].btn-primary { background-color: #{Stylesheet.secondary_dark} !important; border-color: #{Stylesheet.secondary_dark} !important; color: #{Stylesheet.secondary_text_color}; }
|
||||
.btn-warning-full { border-color: #{Stylesheet.secondary}; background-color: #{Stylesheet.secondary}; color: #{Stylesheet.secondary_text_color} !important; }
|
||||
.heading .heading-btn a:hover { background-color: #{Stylesheet.secondary}; color: #{Stylesheet.secondary_text_color}; }
|
||||
.pricing-panel .content .wrap { border-color: #{Stylesheet.secondary}; }
|
||||
.pricing-panel .cta-button .btn:hover, .pricing-panel .cta-button .custom-invoice .modal-body .elements li:hover, .custom-invoice .modal-body .elements .pricing-panel .cta-button li:hover { background-color: #{Stylesheet.secondary} !important; color: #{Stylesheet.secondary_text_color}; }
|
||||
a.label:hover, .form-control.form-control-ui-select .select2-choices a.select2-search-choice:hover, a.label:focus, .form-control.form-control-ui-select .select2-choices a.select2-search-choice:focus { color: #{Stylesheet.primary}; }
|
||||
.about-picture { background: linear-gradient( rgba(255,255,255,0.12), rgba(255,255,255,0.13) ), linear-gradient( #{Stylesheet.primary_with_alpha(0.78)}, #{Stylesheet.primary_with_alpha(0.82)} ), url('/about-fablab.jpg') no-repeat; }
|
||||
.social-icons > div:hover { background-color: #{Stylesheet.secondary}; color: #{Stylesheet.secondary_text_color}; }
|
||||
.profile-top { background: linear-gradient( rgba(255,255,255,0.12), rgba(255,255,255,0.13) ), linear-gradient(#{Stylesheet.primary_with_alpha(0.78)}, #{Stylesheet.primary_with_alpha(0.82)} ), url('#{CustomAsset.get_url('profile-image-file') || '/about-fablab.jpg'}') no-repeat; }
|
||||
.profile-top .social-links a:hover { background-color: #{Stylesheet.secondary} !important; border-color: #{Stylesheet.secondary} !important; color: #{Stylesheet.secondary_text_color}; }
|
||||
section#cookies-modal div.cookies-consent .cookies-actions button.accept { background-color: #{Stylesheet.secondary}; color: #{Stylesheet.secondary_text_color}; }
|
||||
CSS
|
||||
def self.theme_css
|
||||
template = ERB.new(File.read('app/themes/casemate/style.scss.erb')).result
|
||||
engine = SassC::Engine.new(template, style: :compressed)
|
||||
engine.render.presence
|
||||
end
|
||||
|
||||
## ===== HOME PAGE =====
|
||||
@ -149,7 +103,7 @@ class Stylesheet < ApplicationRecord
|
||||
end
|
||||
|
||||
def self.home_page_css
|
||||
engine = Sass::Engine.new(home_style, syntax: :scss)
|
||||
engine = SassC::Engine.new(home_style, style: :compressed)
|
||||
engine.render.presence || '.home-page {}'
|
||||
end
|
||||
end
|
||||
|
295
app/themes/casemate/style.scss.erb
Normal file
295
app/themes/casemate/style.scss.erb
Normal file
@ -0,0 +1,295 @@
|
||||
$primary: <%= Stylesheet.primary %> !default;
|
||||
$primary-light: <%= Stylesheet.primary_light %> !default;
|
||||
$primary-dark: <%= Stylesheet.primary_dark %> !default;
|
||||
|
||||
$secondary: <%= Stylesheet.secondary %> !default;
|
||||
$secondary-light: <%= Stylesheet.secondary_light %> !default;
|
||||
$secondary-dark: <%= Stylesheet.secondary_dark %> !default;
|
||||
|
||||
$primary-text-color: <%= Stylesheet.primary_text_color %> !default;
|
||||
$secondary-text-color: <%= Stylesheet.secondary_text_color %> !default;
|
||||
|
||||
$primary-decoration-color: <%= Stylesheet.primary_decoration_color %> !default;
|
||||
|
||||
.bg-red {
|
||||
background-color: $primary;
|
||||
}
|
||||
|
||||
.bg-red-dark {
|
||||
background-color: $primary;
|
||||
}
|
||||
|
||||
#nav .nav {
|
||||
background-color: $primary;
|
||||
}
|
||||
|
||||
#nav .nav > li > a {
|
||||
color: $primary-text-color;
|
||||
}
|
||||
|
||||
#nav .nav > li > a:hover,
|
||||
#nav .nav > li > a:focus {
|
||||
background-color: $primary-light;
|
||||
color: $primary-text-color;
|
||||
}
|
||||
|
||||
#nav .nav > li > a.active {
|
||||
border-left: 3px solid $primary-dark;
|
||||
background-color: $primary-light;
|
||||
color: $primary-text-color;
|
||||
}
|
||||
|
||||
.nav-primary ul.nav > li.menu-spacer {
|
||||
background: linear-gradient(45deg, $primary-decoration-color, transparent);
|
||||
}
|
||||
|
||||
.nav-primary .text-bordeau {
|
||||
color: $primary-decoration-color;
|
||||
}
|
||||
|
||||
.btn-theme {
|
||||
background-color: $primary;
|
||||
color: $primary-text-color;
|
||||
}
|
||||
|
||||
.btn-theme:active,
|
||||
.btn-theme:hover {
|
||||
background-color: $primary-dark;
|
||||
color: $primary-text-color;
|
||||
}
|
||||
|
||||
.label-theme {
|
||||
background-color: $primary;
|
||||
color: $primary-text-color;
|
||||
}
|
||||
|
||||
.btn-link {
|
||||
color: $primary !important;
|
||||
}
|
||||
|
||||
.btn-link:hover {
|
||||
color: $primary-dark !important;
|
||||
}
|
||||
|
||||
a {
|
||||
color: $primary;
|
||||
}
|
||||
|
||||
.about-page-link a.about-link,
|
||||
.user-profile-nav b.caret {
|
||||
color: $primary;
|
||||
}
|
||||
|
||||
.app-generator a,
|
||||
.home-events h4 a,
|
||||
a.reinit-filters,
|
||||
.pricing-panel a,
|
||||
.calendar-url a,
|
||||
.article a,
|
||||
a.project-author,
|
||||
a.dsq-brlink,
|
||||
.alert a,
|
||||
.about-fablab a,
|
||||
a.collected-infos {
|
||||
color: $primary;
|
||||
}
|
||||
|
||||
.app-generator a:hover,
|
||||
.home-events h4 a:hover,
|
||||
a.reinit-filters:hover,
|
||||
.pricing-panel a:hover,
|
||||
.calendar-url a:hover,
|
||||
.article a:hover,
|
||||
a.project-author:hover,
|
||||
a.dsq-brlink:hover,
|
||||
.widget .widget-content a:hover,
|
||||
.alert a:hover,
|
||||
.about-fablab a:hover,
|
||||
a.collected-infos:hover {
|
||||
color: $primary-dark;
|
||||
}
|
||||
|
||||
.btn.btn-default.reserve-button,
|
||||
.btn.btn-default.show-button,
|
||||
.btn.btn-default.red {
|
||||
color: $primary !important;
|
||||
}
|
||||
|
||||
.nav.nav-tabs .uib-tab.nav-item:not(.active) a {
|
||||
color: $primary;
|
||||
}
|
||||
|
||||
.article h2,
|
||||
.article h3,
|
||||
.article h5 {
|
||||
color: $primary !important;
|
||||
}
|
||||
|
||||
table.table thead tr th a,
|
||||
table.table tbody tr td a:not(.btn) {
|
||||
color: $primary;
|
||||
}
|
||||
|
||||
table.table thead tr th a:hover,
|
||||
table.table tbody tr td a:not(.btn):hover {
|
||||
color: $primary-dark;
|
||||
}
|
||||
|
||||
a:hover,
|
||||
a:focus {
|
||||
color: $primary-dark;
|
||||
}
|
||||
|
||||
h2,
|
||||
h3,
|
||||
h3.red,
|
||||
h5 {
|
||||
color: $primary !important;
|
||||
}
|
||||
|
||||
h5:after {
|
||||
background-color: $primary;
|
||||
}
|
||||
|
||||
.bg-yellow {
|
||||
background-color: $secondary !important;
|
||||
color: $secondary-text-color;
|
||||
}
|
||||
|
||||
.event:hover {
|
||||
background-color: $primary;
|
||||
color: $secondary-text-color;
|
||||
}
|
||||
|
||||
.widget h3 {
|
||||
color: $primary;
|
||||
}
|
||||
|
||||
.modal-header h1,
|
||||
.custom-invoice .modal-header h1 {
|
||||
color: $primary;
|
||||
}
|
||||
|
||||
.block-link:hover,
|
||||
.fc-toolbar .fc-button:hover,
|
||||
.fc-toolbar .fc-button:active,
|
||||
.fc-toolbar .fc-button.fc-state-active {
|
||||
background-color: $secondary;
|
||||
color: $secondary-text-color !important;
|
||||
}
|
||||
|
||||
.block-link:hover .user-name {
|
||||
color: $secondary-text-color !important;
|
||||
}
|
||||
|
||||
.carousel-control:hover,
|
||||
.carousel-control:focus,
|
||||
.carousel-caption .title a:hover {
|
||||
color: $secondary;
|
||||
}
|
||||
|
||||
.well.well-warning {
|
||||
border-color: $secondary;
|
||||
background-color: $secondary;
|
||||
color: $secondary-text-color;
|
||||
}
|
||||
|
||||
.text-yellow {
|
||||
color: $secondary !important;
|
||||
}
|
||||
|
||||
.red {
|
||||
color: $primary !important;
|
||||
}
|
||||
|
||||
.btn-warning,
|
||||
.editable-buttons button[type=submit].btn-primary {
|
||||
background-color: $secondary !important;
|
||||
border-color: $secondary !important;
|
||||
color: $secondary-text-color;
|
||||
}
|
||||
|
||||
.btn-warning:hover,
|
||||
.btn-warning:focus,
|
||||
.btn-warning.focus,
|
||||
.btn-warning:active,
|
||||
.btn-warning.active,
|
||||
.editable-buttons button[type=submit].btn-primary:hover,
|
||||
.editable-buttons button[type=submit].btn-primary:focus,
|
||||
.editable-buttons button.focus[type=submit].btn-primary,
|
||||
.editable-buttons button[type=submit].btn-primary:active,
|
||||
.editable-buttons button.active[type=submit].btn-primary,
|
||||
.open > .btn-warning.dropdown-toggle,
|
||||
.editable-buttons .open > button.dropdown-toggle[type=submit].btn-primary {
|
||||
background-color: $secondary-dark !important;
|
||||
border-color: $secondary-dark !important;
|
||||
color: $secondary-text-color;
|
||||
}
|
||||
|
||||
.btn-warning-full {
|
||||
border-color: $secondary;
|
||||
background-color: $secondary;
|
||||
color: $secondary-text-color !important;
|
||||
}
|
||||
|
||||
.heading .heading-btn a:hover {
|
||||
background-color: $secondary;
|
||||
color: $secondary-text-color;
|
||||
}
|
||||
|
||||
.pricing-panel .content .wrap {
|
||||
border-color: $secondary;
|
||||
}
|
||||
|
||||
.pricing-panel .cta-button .btn:hover,
|
||||
.pricing-panel .cta-button .custom-invoice .modal-body .elements li:hover,
|
||||
.custom-invoice .modal-body .elements .pricing-panel .cta-button li:hover {
|
||||
background-color: $secondary !important;
|
||||
color: $secondary-text-color;
|
||||
}
|
||||
|
||||
a.label:hover,
|
||||
a.label:focus,
|
||||
.form-control.form-control-ui-select .select2-choices a.select2-search-choice:hover,
|
||||
.form-control.form-control-ui-select .select2-choices a.select2-search-choice:focus {
|
||||
color: $primary;
|
||||
}
|
||||
|
||||
.about-picture {
|
||||
background: linear-gradient( rgba(255,255,255,0.12), rgba(255,255,255,0.13) ),
|
||||
linear-gradient(<%=Stylesheet.primary_with_alpha(0.78)%>, <%=Stylesheet.primary_with_alpha(0.82)%>),
|
||||
url('/about-fablab.jpg') no-repeat;
|
||||
}
|
||||
|
||||
.social-icons > div:hover {
|
||||
background-color: $secondary;
|
||||
color: $secondary-text-color;
|
||||
}
|
||||
|
||||
.profile-top {
|
||||
background: linear-gradient( rgba(255,255,255,0.12), rgba(255,255,255,0.13) ),
|
||||
linear-gradient(<%=Stylesheet.primary_with_alpha(0.78)%>, <%=Stylesheet.primary_with_alpha(0.82)%>),
|
||||
url("<%=CustomAsset.get_url('profile-image-file') || '/about-fablab.jpg'%>") no-repeat;
|
||||
}
|
||||
|
||||
.profile-top .social-links a:hover {
|
||||
background-color: $secondary !important;
|
||||
border-color: $secondary !important;
|
||||
color: $secondary-text-color;
|
||||
}
|
||||
|
||||
section#cookies-modal div.cookies-consent .cookies-actions button.accept {
|
||||
background-color: $secondary;
|
||||
color: $secondary-text-color;
|
||||
}
|
||||
|
||||
.pricing-panel {
|
||||
.cta-button {
|
||||
button.subscribe-button {
|
||||
border-color: $secondary;
|
||||
&.selected-card {
|
||||
background-color: $secondary;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -65,7 +65,7 @@ if member.subscription
|
||||
json.expired_at member.subscription.expired_at.iso8601
|
||||
json.canceled_at member.subscription.canceled_at.iso8601 if member.subscription.canceled_at
|
||||
json.stripe member.subscription.stp_subscription_id.present?
|
||||
json.plan do
|
||||
json.plan do # TODO, refactor: duplicates subscribed_plan
|
||||
json.id member.subscription.plan.id
|
||||
json.base_name member.subscription.plan.base_name
|
||||
json.name member.subscription.plan.name
|
||||
@ -82,4 +82,5 @@ json.machine_credits member.machine_credits do |mc|
|
||||
json.machine_id mc.creditable_id
|
||||
json.hours_used mc.users_credits.find_by(user_id: member.id).hours_used
|
||||
end
|
||||
# TODO, missing space_credits?
|
||||
json.last_sign_in_at member.last_sign_in_at.iso8601 if member.last_sign_in_at
|
||||
|
@ -40,7 +40,7 @@ json.all_projects @member.all_projects do |project|
|
||||
if requested_current || project.state == 'published'
|
||||
json.extract! project, :id, :name, :description, :licence_id, :slug, :state
|
||||
json.author_id project.author.user_id
|
||||
|
||||
|
||||
json.project_image project.project_image.attachment.large.url if project.project_image
|
||||
json.machine_ids project.machine_ids
|
||||
json.machines project.machines do |m|
|
||||
|
Loading…
x
Reference in New Issue
Block a user