@mortendk #drupaltwig - drupalcon | be human, think … · theming drupalcon barcelona 2015 drupal...
TRANSCRIPT
@moRtenDk #drUpaltWIG
7
@moRtenDk #drUpaltWIG
tHemIngDRUpALCoN BaRCElONA 2015
DRUpAl 8
@moRtenDk #drUpaltWIG
SLIdES aRE oNLInE In 60 MInUTEs
sLidEs
@moRtenDk #drUpaltWIG
@morTenDk
CLAsSy MAInTAInER
GEEk RÖYALe THE ANGrY
THEmER
TaG1 CONsULTiNG
@moRtenDk #drUpaltWIG
@MOrTENdK
@moRtenDk #drUpaltWIG
#DRuPALtWiG
@moRtenDk #drUpaltWIG
sOrryRc 1
@moRtenDk #drUpaltWIG
bOoOOooOoLET THE ANGeR OuT
@moRtenDk #drUpaltWIG
sTocKhoLm sYndRome
@moRtenDk #drUpaltWIG
DRUpAL7 MARkUP
@moRtenDk #drUpaltWIG
“IT’S A FEAtUrE”
dIviTis<DIV><DIV><DIV><DIV><DIV><DIV><DIV><DIV><DIV><DIV><DIV><DIV><DIV><DIV><DIV><DIV><DIV><DIV><DIV><DIV><DIV><DIV><DIV><DIV><DIV><DIV><DIV><DIV><DIV><DIV>
</DIV></DIV></DIV></DIV></DIV></DIV></DIV></DIV></DIV></DIV></DIV></DIV>
@moRtenDk #drUpaltWIG
5000LINeS Of PHpTEMpLATe.PHp
TotAllY oK
@moRtenDk #drUpaltWIG
<div class=“foo bar baz foo-more-more bar-more-yet another one”>
fEatUreTHE CLAsS SoUP IS AnOTHeR
@moRtenDk #drUpaltWIG
nO mOre aAaaRgh!
@moRtenDk #drUpaltWIG
nEw
tHemE eNgiNe
GOOd-BYe PHPtEMPlAtEHELlO TwIG
@moRtenDk #drUpaltWIG
tHemE fUncTioNs
dEad!
@moRtenDk #drUpaltWIG
tWig tEmpLatEs
EVErYTHiNG iS
BLOcK.HtML.tWiG
MARk.HTmL.TwIG
TABlE.HtML.tWiG
PAGe.HTmL.TwIGNODe.HTmL.TwIG
VIEw.HTmL.TwIG
FIElD.HtML.tWiG IMAgE-WiDGEt.HTmL.TwIG
@moRtenDk #drUpaltWIG
tHemE iS iN cOntRolThE
OF mARKuP & CSs
@moRtenDk #drUpaltWIG
uNleArn pHptEmpLa
te<? pHP dIe(‘PHPtEMPlAtE’) ?>
@moRtenDk #drUpaltWIG
REAdY?
@moRtenDk #drUpaltWIG
tWigDRUpAl 8
@moRtenDk #drUpaltWIG
IS a “MODeRN” TEmPLAtE LaNGUaGe -> sYMPhONY
USEd BY OTHeR SySTEmS + It’S EaSY tO LeARN :)
tWig
@moRtenDk #drUpaltWIG
{{ var }} {# comment #}
{% functionality %}
{ # %
@moRtenDk #drUpaltWIG
{{ data.is.here }}
{{ also.this[#hashtags] }}
vAr DriLliNg$yo[‘drupal_where ’]->is[‘und’][0]->my_data7
@moRtenDk #drUpaltWIG
{{ var|makemepretty(‘now’) }}
fUncTionPIPe
TWIg FUnCTIoNVaR
@moRtenDk #drUpaltWIG
{{ username|uppercase }}
MORTENDK
fUncTion(mortendk)
@moRtenDk #drUpaltWIG
{{ ‘Copenhagen’|t }}
{% trans %} by {{ user }} date {{ date }} {% endtrans %}
tRanSlaTe
@moRtenDk #drUpaltWIG
{% if person=“mortendk” %} <h1>Loves Drupal8</h1> {% endif %}
cOntRol
@moRtenDk #drUpaltWIG
{{ sushi|raw}}
aUtoEscApe
SECuRITy IS SOMeTHInG DEVeLOPeRS LIKe
@moRtenDk #drUpaltWIG
{% set foo = “bar” %}
{{ foo }}
bar
cReaTe Var
@moRtenDk #drUpaltWIG
cLasSyTHE DRUpAl 8 BAsE ThEmE
@moRtenDk #drUpaltWIG
7corE
claSsy
<HTmL> .CSs CLAsS=“FoO”
<HTmL> .CSs CLAsS=“FoO”
@moRtenDk #drUpaltWIG
bAseTheMe
corE claSsy
my ThemE
? barTik
sevEn$VArS
@moRtenDk #drUpaltWIG
bAseTheMe
<div> {{ foo }} </div>
corE claSsy“MY tHEMe”
NO bASEtHEMe DEfINEd
@moRtenDk #drUpaltWIG
bAseTheMe
<div class=“node node—article”> {{ foo }} </div>
corE claSsy“MY tHEMe”
BASe THeME: CLAsSY
@moRtenDk #drUpaltWIG
tEmpLatEs
CORe/THeME/cLASsY/*
MODuLES/[MODuLENaME]/*7aniMatiOn eXplaIninG how we MoveD shIt
outTa cOre And Into claSsy
@moRtenDk #drUpaltWIG
dRupAl8 teMplAtes
CORe/THeMES/CLAsSy/
@moRtenDk #drUpaltWIG
dEfiNe BasEthEme
base theme: classy
[THEmENAmE].iNFO.YmL
@moRtenDk #drUpaltWIG
yOu DecIde!
corE claSsy
CLEaN As COrE CLAsSES YOU CAN TRUsT
@moRtenDk #drUpaltWIG
corE
claSsy
7
ZeN
MOThERShIP
wAitAmiNutE!
@moRtenDk #drUpaltWIG
MORtENDk
JOHn ALbIN
corE
claSsy
7
ZeN
MOThERShIP
MAInTAInERS ?
@moRtenDk #drUpaltWIG
@moRtenDk #drUpaltWIG
sEtupSETtING UP a THeME
@moRtenDk #drUpaltWIG
[ROOt]/ThEMEs/[THEmENAmE]
I LiVE wHERe NOw ?
@moRtenDk #drUpaltWIG
tHemE cOnfIg FilEs
*.InFO.yMl *.LiBRArIES.YML *.BrEAKpOINtS.YmL *.ThEmE
@moRtenDk #drUpaltWIG
*.inFo.YmlTHEmE CoNFIgURAtION, CSs & jS
@moRtenDk #drUpaltWIG
BASiC INFo
REGiOnS
LIBrARIeS
REMoVE cSS
@moRtenDk #drUpaltWIG
@moRtenDk #drUpaltWIG
*.liBraRieS.yMlADDiNG jS & CSs TO THE THEmE
@moRtenDk #drUpaltWIG
FOO.INFo.YAmL
FOO.LIBrARIeS.YaML
SLIdER.cSSSLIdER.jS
SLIdER
FOO.CsSBAR.JS
AWEsOmE
@moRtenDk #drUpaltWIG
.INfO.YmL
.LIbRARiES.yML
@moRtenDk #drUpaltWIG
NAMe
DEPeNDEnCIEs
CSS FILeS
*.liBraRieS.yMl
JS fILEs
@moRtenDk #drUpaltWIG
global: version: VERSION css: component: css/user/user.theme.css: {} theme: css/layout.css: {}
cSs OrgAniZingBASe LAYoUt COMpONEnT STAtE THEmE
@moRtenDk #drUpaltWIG
[*].BreAkpOinTs.YmlRESpONSiVE iMAGeS
@moRtenDk #drUpaltWIG
*.BrEAKpOINtS.YmL
@moRtenDk #drUpaltWIG
*.BrEAKpOINtS.YmL
@moRtenDk #drUpaltWIG
[*].TheMe
WAS PHPtEMPlATE.PhP
@moRtenDk #drUpaltWIG
.TheMe
.LIbRARiES.yML
.THeME
@moRtenDk #drUpaltWIG
tOolsHOW TO fIND STUfF & DEbUg
@moRtenDk #drUpaltWIG
sEttIngS.pHp
if (file_exists(__DIR__ . '/settings.local.php')) { include __DIR__ . '/settings.local.php'; }
COPy: SiTES/EXAmPLE.SETtINGs.LOcAL.pHP
TO: SITeS/DeFAUlT/SeTTInGS.lOCAl.PHp
UNCoMMEnT In SEtTINgS.PhP
@moRtenDk #drUpaltWIG
DOWnLOAd DEvEL mODUlE INStALL DEVeL + KINt
INStALL DRUsH DRUsH En KInT
DOCs.DRuSH.oRG/eN/MaSTEr/INsTALl/
dEvel
@moRtenDk #drUpaltWIG
dIsaBle csS cAche
@moRtenDk #drUpaltWIG
THEmE DeBUG FTW!
SERvICEs.YMl
@moRtenDk #drUpaltWIG
FILe NAmE SuGGEsTIOnSFILe NAmE SuGGEsTIOnS
@moRtenDk #drUpaltWIG
PATh TO ACTiVE tEMPlAtE
@moRtenDk #drUpaltWIG
@moRtenDk #drUpaltWIG
kInt{{ kint( foo ) }}
KRUmO FoR DrUPAl 8
{{ content.field_image }}
screenshot af kint fra video
@moRtenDk #drUpaltWIG
SITeS/AlL/DeFAUlT/SeRVIcES.yMl
DRUsH Cr
{{ KInT(FoO) }}
tWig deBug:
@moRtenDk #drUpaltWIG
tEmpLatE sTruCtuRe
EVErYTHiNG iS A TEMpLATe FIlE
@moRtenDk #drUpaltWIG
125 TemPlaTesWE nUKEd THe THeME fUNCtIONs*
TURnED iT AlL INTo A mETRiCFUCkTON
OF tEMPlATEs
@moRtenDk #drUpaltWIG
@moRtenDk #drUpaltWIG
gRouPsdo we really need this here ?
@moRtenDk #drUpaltWIG
tEmpLatE gRouPsLAYoUT
FIElD
DATaSeT
VIEwS
BLOcK CONtENT-EDIt
CONtEnT
MISc
USEr
NAViGATiON
FORm
@moRtenDk #drUpaltWIG
hTml
HTMl.HTmL.TwIG
CSS + Js
HEAdER
@moRtenDk #drUpaltWIG
HTMl.HTmL.TwIG
pAge
PAGe.HTmL.TwIG
@moRtenDk #drUpaltWIG
HTMl.HTmL.TwIGREGiON.hTML.TWIg
REGiON.hTML.TWIg
REGiON.hTML.TWIg
rEgiOn's
PAGe.HTmL.TwIG
@moRtenDk #drUpaltWIG
HTMl.HTmL.TwIG
cOntEnt
BLOcK.HtML.tWiG NODe.HTmL.TwIG VIEw.HTmL.TwIG
REGiON.hTML.TWIg
@moRtenDk #drUpaltWIG
nOde
FIElD.HtML.tWiG
NODe.HTmL.TwIG
FIElD.HtML.tWiGFIElD.HtML.tWiG
FIElD-—IMAgE.HtML.tWiGFIElD.HtML.tWiG
FIElD.HtML.tWiG
@moRtenDk #drUpaltWIG
aLl The fiEldsFIElD.HtML.tWiG FIElD.HtML.tWiG FIElD.HtML.tWiG FIElD.HtML.tWiG
FIElD.HtML.tWiG FIElD.HtML.tWiG FIElD.HtML.tWiG FIElD.HtML.tWiG
FIElD.HtML.tWiG FIElD.HtML.tWiG FIElD.HtML.tWiG FIElD.HtML.tWiG
FIElD.HtML.tWiG FIElD.HtML.tWiG FIElD.HtML.tWiG FIElD.HtML.tWiG
WE’RE gONNa TAlK AbOUT FIElDS lATEr
@moRtenDk #drUpaltWIG
lAyoUtTHE MAGiC Of WItHOUt
@moRtenDk #drUpaltWIG
{{ content|without(‘field’) }}
wIthOut fuNctIonPIPe
NAMeTWIg FUnCTIoN
VaR
@moRtenDk #drUpaltWIG
NODe.HTmL.TwIG
@moRtenDk #drUpaltWIG
conTeNt
imaGe
tagS
wIthOut
@moRtenDk #drUpaltWIG
{{ coNtenT }}
{{ imAge }}
{{ content }}
{{ teXt }} {{ taGs }}
@moRtenDk #drUpaltWIG
{{ coNtenT | WithOut(*) }}
{{ imAge }}
{{ content|without(‘image’) }}
{{ content.image }}
{{ teXt }} {{ taGs }}
@moRtenDk #drUpaltWIG
{{ coNtenT | WithOut(**) }}
{{ imAge }}
{{ content|without(‘image’,‘tags’) }}
{{ content.image }}
{{ teXt }} {{ taGs }}
{{ content.tags }}
@moRtenDk #drUpaltWIG
{{ coNtenT | WithOut(**) }}
{{ imAge }}
{{ content|without(‘image’,‘tags’) }}
{{ content.image }}
{{ teXt }} {{ taGs }}
{{ content.tags }}
{{ neW }}
NEW FIElD
@moRtenDk #drUpaltWIG
CONtEnTnOde.htMl.Twig
@moRtenDk #drUpaltWIG
CONtENT.FIElD_ImAgE
@moRtenDk #drUpaltWIG
CONtENT.FIElD_TaGS
@moRtenDk #drUpaltWIG
fIeldTHE HEArT Of DRuPaL
@moRtenDk #drUpaltWIG
HOW MANy <DiV>S DOEs IT TAKe TO MAKe A “SINgLE fIELd WItH OnE
VaLuE” NO lABEl?
@moRtenDk #drUpaltWIG
@moRtenDk #drUpaltWIG
Yo!
@moRtenDk #drUpaltWIG
Yo!
<div class=“field-items”>
</div>
<div class=“field field-name-field-single field-type-text field-label-hidden”>
</div>
</div>
<div class=“field-item even”> 7
@moRtenDk #drUpaltWIG
Yo!
<div class=“field field--name-field-single field--type-string field--label-hidden field__items”>
</div> CLAsSY
@moRtenDk #drUpaltWIG
Yo!<div> </div>
@moRtenDk #drUpaltWIG
Yo!<div> </div>
ONE DIV ZERo CLaSSEs 100% DrUPAl
@moRtenDk #drUpaltWIG
Yo!<div class=“yolo”> </div>
ONE DIV ZERo CLaSSEs 100% DrUPAl
@moRtenDk #drUpaltWIG
sIngLenAked
WHAt DO I UsE A
<DIv>
dUde grEat
@moRtenDk #drUpaltWIG
WHAtEVErYOU
WANt IT TO
@moRtenDk #drUpaltWIG
fIelD mArkUp
@moRtenDk #drUpaltWIG
fIeldLABeL VALuE
@moRtenDk #drUpaltWIG
SINgLE
MULtIPLe
LABeL
LABeL
}}
@moRtenDk #drUpaltWIG
FIElD.HtML.tWiG
@moRtenDk #drUpaltWIG
SINgLE MULtIPLe
SINgLE + LAbEL MULtIPLe + lABEl
@moRtenDk #drUpaltWIG
LABeL DiSPLaY
mAnaGe DisPlay
@moRtenDk #drUpaltWIG
“INLiNE”
“VISuALLy HIDdEN”
“ABOvE”
@moRtenDk #drUpaltWIG
FIElD.HtML.tWiG
@moRtenDk #drUpaltWIG
NO lABEl
LABeL
@moRtenDk #drUpaltWIG
{% if label_hidden %} {% if multiple %}
{% else %} {% endif %} {% else %} {% if multiple %}
{% else %}
{% endif %} {% endif %}
@moRtenDk #drUpaltWIG
<div> yo </div>
<div> <div> label</div> <div>yo </div> </div>
<div> <div>label</div> <div> <div>yo </div> <div>lo </div> </div> </div>
@moRtenDk #drUpaltWIG
aTtrIbuTesPURe CLaSS
@moRtenDk #drUpaltWIG
<div {{ attributes }}> class=“foo” data-drupal-foo aria-hidden=“true”
aTtrIbuTes
@moRtenDk #drUpaltWIG
CLAsSY
<DIv CLaSs=“FOO FOO-BAR FOO-BAR-BaZ”>
*.TpL.PhP
THEmE FuNCTiOnS
PREpROCeSS
$VArS
DRUpAL7
7
@moRtenDk #drUpaltWIG
@moRtenDk #drUpaltWIG
{% set classes = [ ‘field-' ~ field_name|clean_class ~ ' ] %}
<div {{ attributes.addClass(classes) }}>…</div>
<div class=“tags field-tags”>…
aDdcLass
@moRtenDk #drUpaltWIG
<i {{ attributes.removeClass(red) }}> … </i>
<i class=“blue”>…</i>
<div class=“red blue”> … </div>BAD MODuLE oUTPuT
rEmoVe ClaSs
@moRtenDk #drUpaltWIG
CLAsSYMODuLECORe
<DIv CLaSs=“CORe”>
ESSeNTIaL ClASSeS Ex: “IS-vISIbLE”
@moRtenDk #drUpaltWIG
CLAsSYMODuLECORe
<DIv CLaSs=“CORe MOdUlE”>
$vaR[‘attRibuTes’]->AddCLass(‘modUle’)
@moRtenDk #drUpaltWIG
CLAsSYMODuLECORe
<DIv CLaSs=“CORe MOdULE THEmE”>
{{ ATtRIBuTES.ADDcLASs(‘THEmE’) }}
@moRtenDk #drUpaltWIG
CLAsSYMODuLECORe
<DIv CLaSs=“CORe THeME”>
{{ ATtRIBuTES.REMoVe(‘MODuLE’) }}
@moRtenDk #drUpaltWIG
CLAsSYMODuLECORe
<DIv CLaSs=“THEmE”>
{{ ATtRIBuTES.REMoVe(‘MODuLE’,’CORe’) }}
@moRtenDk #drUpaltWIG
jS- PreFix
<DIv CLaSs=“JS-fOO fOO”>…
$(.jS-FoO) .FOo{…}
@moRtenDk #drUpaltWIG
<div class="blablabla"> {{ attributes .removeClass(‘blablabla’) .addClass(‘hero-main’) .setAttribute('id', 'top') }} <div id="top" class="hero-main">
aTtrIbuTes
@moRtenDk #drUpaltWIG
fIelD & atTriButEs
KISsING IN a TReEEEeEEEeEEEeE
@moRtenDk #drUpaltWIG
<div> yo </div>
<div> <div> label</div> <div>yo </div> </div>
<div> <div>label</div> <div> <div>yo </div> <div>hej </div> </div> </div>
@moRtenDk #drUpaltWIG
<div class=“field field__item”> yo </div>
<div class=“field”> <div class=“field__label”> label</div> <div class=“field__item”>yo </div> </div>
<div class=“field”> <div class=“field__label”>label</div> <div class=“field__items”> <div class=“field__item”>yo </div> <div class=“field__item”>lo </div> </div> </div>
@moRtenDk #drUpaltWIG
LABeL VALuE
.field__item.field__label
.field
@moRtenDk #drUpaltWIG
.field__item.field__label
.field__items
.field
@moRtenDk #drUpaltWIG
FIX THE MARkUP
@moRtenDk #drUpaltWIG
@moRtenDk #drUpaltWIG
ADD & REmOVE CLAsSES
@moRtenDk #drUpaltWIG
@moRtenDk #drUpaltWIG
CHAnGE sTUFf WHeN 8
@moRtenDk #drUpaltWIG
@moRtenDk #drUpaltWIG
{{ attach_library('classy/book-navigation') }}
cSs FilEs In TemPlaTe
@moRtenDk #drUpaltWIG
tWigBloCkMORe COoLNEsS FrOM tWiG
@moRtenDk #drUpaltWIG
datA (pAge.Html.twiG)
PAGe.HTmL.TwIGD8
datA (pAge.Html.twiG)
@moRtenDk #drUpaltWIG
datA (pAge.Html.twiG)
{% block foo %} {% endblock %}
PAGe.HTmL.TwIGD8
datA (pAge.Html.twiG)
@moRtenDk #drUpaltWIG
datA (pAge.Html.twiG)
(paGe-—froNt.hTml.Twig)
{% extends "page.html.twig" %}
PAGe.HTmL.TwIGD8
datA (pAge.Html.twiG)
@moRtenDk #drUpaltWiG
@moRtenDk #drUpaltWIG
PAGe.HTmL.TwIG
PAGe—FROnT.HtML.tWiG
@moRtenDk #drUpaltWIG
PAGe.HTmL.TwIG
PAGe—FROnT.HtML.tWiG
@moRtenDk #drUpaltWIG
hAppY ?ARE YOU NOT ENTeRTAiNED ?
@moRtenDk #drUpaltWiG
SCReENShOt 2.0
@moRtenDk #drUpaltWiG
mEnupAgeRs
ONLy 1 (OnE) tEMPlATE FILe
MENu.HTmL.TwIG
@moRtenDk #drUpaltWiG
pAgerFUN FOR EVErYBOdY ?PAGeR.HtML.tWiG
@moRtenDk #drUpaltWIG
8 thIngS cHanGed
T L ; D L TOO LONg - DIDn'T lISTeN!
@moRtenDk #drUpaltWIG
1. iE sUppOrt?
NO mORE SUPpORT FOR IE6, Ie7 & iE8
@moRtenDk #drUpaltWIG
2. mArkUp CleAnup
HTMl5 CSS IS sMACsS & BEm BAsEd
“MODeRN” PRaCTIcE #iD ReMOVeD SEVeN Is REsPONsIvE
@moRtenDk #drUpaltWIG
jS sEpeRatIonSEPaRATeD
JAVaSCRiPT’S FuNCTiONAlITY CSS STYlING IS sEPArATEd
.JS-FOObAR{ …} .FOoBaR{ COlOR: BLUe}
@moRtenDk #drUpaltWIG
dIviTis
90% OF tHE mARKuP Is GOnE
@moRtenDk #drUpaltWIG
jQueRy DepEndEncy
DONt WAnT 32K Of LOvE ? … THeN DoN’T
@moRtenDk #drUpaltWIG
cLasSy!
CLAsSY SEPaRATeD ThE MaRKUp
FROm COrE
@moRtenDk #drUpaltWIG
sAluTe!FOR THOsE ThAT rOCKeD ThE TwIG
WE sALUtE YoU!
@moRtenDk #drUpaltWIG
i loOovE uUuCOTtSeR
JOEl
LEWiS
EMMa
LAUrII
#FReERUbEN
DAViD HeRNAnDeZ
JOHn ALbINWIM LEErS
JEN LAMpToN
FABiAN
@moRtenDk #drUpaltWiG
DRUpAl 7
@moRtenDk #drUpaltWIG
DRUpAL.oRG/tHEMe-GUiDe/8
DRUpAL.oRG/cODInG-StANDaRDS/CSS
SMAcSS.cOM
TWIg.SEnSIOlABS.ORG/DOCuMENtATIoN
lInks
@moRtenDk #drUpaltWIG
dOwnLoaD d8
BUIlD StUFF NOW!
DRUpAL.oRG/dRUPaL8
@moRtenDk #drUpaltWIG
WEEkLY mEETiNG’S THUrSDAy 17:00 CEt
#DruPalTwig
@moRtenDk #drUpaltWIG
USE TWItTER #DRuPALtWIG
QUEsTIOnS, cOMMeNTS & FEeDBAcK @MOrTENdK
qUesTioNs
@moRtenDk #drUpaltWiG
sEssIonsDRUpALCoN
@moRtenDk #drUpaltWiG
FROnTENd UNiTED BELuGAM
BOF ROOm XXx
FROnTENd UNiTeD
@moRtenDk #drUpaltWiG
ALL WEEk !DRUpAL fRONtEND SPRiNt
CODeR LoUNGe
SPRiNT lEADeRs:(FRoNTEnD UnITEd)
@moRtenDk #drUpaltWIG
FONtS: DAFt BRuSH, BRUsH Up, BiTTEr
ICOnS: SMAlL IcONS 2
cRedIts