Skip to content

Instantly share code, notes, and snippets.

@MarvNC
Last active July 21, 2023 17:24
Show Gist options
  • Save MarvNC/a2ab5ffc190efc264a3782211cc68763 to your computer and use it in GitHub Desktop.
Save MarvNC/a2ab5ffc190efc264a3782211cc68763 to your computer and use it in GitHub Desktop.
Mandarin 5k HSK Deck Styling

Mandarin 5k HSK Deck Styling

Styling for the deck found here.

Needs persistence downloaded and put in the collection.media folder with the filename __persistence.js for swapping to persist to the backside, but it'll work fine without it, just without the state changing on the back side properly.

It'll randomize whether the simplified or traditional is shown first on the front side, and then swap their order on the back side to maximise recognition for both.

It also supports tone colorizing from this reddit post. Just remove the last <script> tag from the back.html file if you don't want it. The current codes are from Pleco but you can change them to whatever you want.

anki_Preview_2023-02-09_12-42-43

<div class="hanzi">
<span class="traditional hanzi">{{Traditional}}</span>
<span class="separator"><br /></span>
<span class="simplified hanzi">{{Simplified}}</span>
</div>
<span style="font-size: 22px; color: #ffaa00">{{Homograph}}</span>
<div class="pinyin">{{Pinyin.1}}</div>
<div class="english">{{Meaning}}</div>
<div class="description">{{Part of speech}}</div>
<hr />
<div class="sentence traditional">{{SentenceTraditional}}</div>
<div class="sentence simplified">{{SentenceSimplified}}</div>
<div class="pinyinSen">{{SentencePinyin.1}}</div>
<div class="meaningSent">{{SentenceMeaning}}</div>
{{Audio}} {{SentenceAudio}}
<br />
<div class="image">{{SentenceImage}}</div>
<script src="__persistence.js"></script>
<script>
// get swap state from front side, and do the opposite
(() => {
// save swap state for backside
let persistenceLoaded = false;
setInterval(() => {
if (!persistenceLoaded) {
if (typeof Persistence == 'undefined') return;
persistenceLoaded = true;
if (Persistence.isAvailable()) {
const swap = Persistence.getItem();
// do opposite
swapPositions(!swap);
}
}
}, 50);
})();
function swapPositions(swap) {
if (swap) {
const traditional = document.querySelector('.traditional');
const separator = document.querySelector('.separator');
const simplified = document.querySelector('.simplified');
// swap their locations in the DOM
simplified.after(separator);
separator.after(traditional);
const tradSentence = document.querySelector('.sentence.traditional');
const simpSentence = document.querySelector('.sentence.simplified');
simpSentence.after(tradSentence);
}
}
</script>
<!-- Pitch colorizer -->
<script>
(() => {
// Modified from https://www.reddit.com/r/Anki/comments/i6rmp6/chinese_flashcards_automatic_coloring_according/ by /u/Destroyer862K2
// Edited to work with multiple hanzi and sentence elements
// Edit to change colors, currently using Pleco colors
const color_codes = {
1: '#e30000',
2: '#02b31c',
3: '#1510f0',
4: '#8900bf',
5: '#777777',
};
// MDBG codes
// const color_codes = {
// 1: '#FF0000',
// 2: '#D09000',
// 3: '#00AA00',
// 4: '#0044FF',
// 5: '#696969',
// };
decode_pinyin = function (pinyin) {
const core = ['a', 'e', 'i', 'o', 'u', 'ü'];
let arr = pinyin.replace(/<b>|<\/b>|<div>|<\/div>/g, '').split('');
is_core = function (c, c_previous_two = '', c_next = '') {
//pre conditions
if (
c == 'r' &&
(c_next == ' ' || c_next == '') &&
c_previous_two != ' ' &&
c_previous_two != ''
) {
return [true, true];
}
//pre conditions
c = c
.normalize('NFD')
.replace(/[\u0300-\u036f]/g, '')
.toLowerCase();
for (let i = 0; i < core.length; i++) {
if (c === core[i]) {
return [true, false];
}
}
return [false, false];
};
get_tone = function (str) {
let pure = str.replace(/a|e|i|o|u|ü|r/g, '');
if (pure == '') {
return 5;
} else if (['ā', 'ē', 'ī', 'ō', 'ū', 'ǖ'].includes(pure)) {
return 1;
} else if (['á', 'é', 'í', 'ó', 'ú', 'ǘ'].includes(pure)) {
return 2;
} else if (['ǎ', 'ě', 'ǐ', 'ǒ', 'ǔ', 'ǚ'].includes(pure)) {
return 3;
} else if (['à', 'è', 'ì', 'ò', 'ù', 'ǜ'].includes(pure)) {
return 4;
}
return pure;
};
let tones_arr = [];
let buff = [];
flush = function () {
if (buff.length > 0) {
tones_arr.push(get_tone(buff.join('')));
buff = [];
}
};
for (let i = 0; i < arr.length; i++) {
let res = is_core(arr[i], arr[i - 2], arr[i + 1]);
if (res[1]) {
flush();
}
if (res[0]) {
buff.push(arr[i]);
} else {
flush();
}
}
if (buff.length > 0) {
tones_arr.push(get_tone(buff.join('')));
buff = [];
}
return tones_arr;
};
recolor_pinyin = function (pinyin_element, hanzi_element) {
let hanzi_sentence = hanzi_element.innerHTML;
let decoded = decode_pinyin(pinyin_element.innerHTML);
let hanzi_sentence_strip = hanzi_sentence.replace(
/ |<b>|<\/b>|\.|。|\?|?|!|!|<div>|<\/div>|,|,/g,
''
);
if (hanzi_sentence_strip.length == decoded.length) {
let start = 0;
for (i in hanzi_sentence_strip) {
let index = hanzi_sentence.indexOf(hanzi_sentence_strip[i], start);
let insertion =
'<span style="color:' +
color_codes[decoded[i]] +
';">' +
hanzi_sentence_strip[i] +
'</span>';
hanzi_sentence =
hanzi_sentence.substring(0, index) + insertion + hanzi_sentence.substring(index + 1);
start = index + insertion.length;
}
hanzi_element.innerHTML = hanzi_sentence;
}
};
let pinyin_element = document.querySelector('.pinyin');
let hanzi_elements = [...document.querySelectorAll('.hanzi')];
let pinyin_sentence_element = document.querySelector('.pinyinSen');
let hanzi_sentence_elements = [...document.querySelectorAll('.sentence')];
if (pinyin_element != null && hanzi_elements.length > 0) {
for (const hanzi_element of hanzi_elements) {
recolor_pinyin(pinyin_element, hanzi_element);
}
}
if (pinyin_sentence_element != null && hanzi_sentence_elements.length > 0) {
for (const hanzi_sentence_element of hanzi_sentence_elements) {
recolor_pinyin(pinyin_sentence_element, hanzi_sentence_element);
}
}
})();
</script>
<div class="hanzi">
<span class="traditional">{{Traditional}}</span>
<span class="separator"><br /></span>
<span class="simplified">{{Simplified}}</span>
</div>
<span style="position: absolute; font-size: 22px; color: #ffaa00; transform: translateY(60px)"
>{{Homograph}}</span
>
<div class="pinyin"><br /></div>
<div class="english"><br /></div>
<div class="description"><br /></div>
<hr />
<div class="sentence traditional">{{SentenceTraditional}}</div>
<div class="sentence simplified">{{SentenceSimplified}}</div>
<div class="pinyinSen"><br /></div>
<script src="__persistence.js"></script>
<script>
// swap traditional and simplified at random
(() => {
const swap = Math.random() > 0.5;
swapPositions(swap);
// save swap state for backside
let persistenceLoaded = false;
setInterval(() => {
if (!persistenceLoaded) {
if (typeof Persistence == 'undefined') return;
persistenceLoaded = true;
if (Persistence.isAvailable()) {
Persistence.setItem(swap);
}
}
}, 50);
})();
function swapPositions(swap) {
if (swap) {
const traditional = document.querySelector('.traditional');
const separator = document.querySelector('.separator');
const simplified = document.querySelector('.simplified');
// swap their locations in the DOM
simplified.after(separator);
separator.after(traditional);
const tradSentence = document.querySelector('.sentence.traditional');
const simpSentence = document.querySelector('.sentence.simplified');
simpSentence.after(tradSentence);
}
}
</script>
@import url('https://fonts.googleapis.com/css2?family=Noto+Sans+TC&display=swap');
@import url('https://fonts.googleapis.com/css2?family=Noto+Sans+SC&display=swap');
hr {
height: 3px;
background: black;
border: none;
margin-top: 20px;
margin-bottom: 20px;
}
div {
margin-bottom: 10px;
}
.card {
font-family: 'Noto Sans TC', sans-serif;
font-size: 10px;
text-align: left;
background-color: white;
color: black;
padding: 20px;
max-width: 1000px;
margin: auto;
}
.hanzi {
font-size: 78px;
border-bottom: 3px solid rgba(0, 0, 0, 0);
transition: border 0.5s ease, padding 0.5s ease;
margin-top: 20px;
}
.simplified {
font-family: 'Noto Sans SC' !important;
}
.hanzi.whover span.simplified {
/* color: rgb(123, 123, 123); */
}
.hanzi.whover {
cursor: pointer;
}
.hanzi.whover:hover {
}
.hanzi.whover::before {
content: var(--pinyin);
position: absolute;
font-size: 22px;
color: #55dd55;
padding-left: 10px;
padding-right: 10px;
padding-bottom: 5px;
border-left: 3px solid black;
transform: translate(-10px, -40px);
opacity: 0;
transition: opacity 0.5s ease;
height: 140px;
padding-top: 0px;
}
.hanzi.whover:hover::before {
opacity: 1;
}
.sentence {
font-size: 30px;
text-align: left;
transition: padding 0.5s ease;
}
.pinyinSen.whover {
cursor: pointer;
opacity: 1;
border-left: 3px solid black;
padding-left: 10px;
height: 25px;
max-height: 80px;
display: flex;
padding-top: 55px;
transform: translate(-10px, -50px);
opacity: 0;
transition: opacity 0.5s ease;
black-space: nowrap;
}
.pinyinSen.whover:hover {
opacity: 1;
}
.pinyin {
font-size: 22px;
color: #55dd55;
}
.pinyinSen {
font-size: 20px;
color: #55dd55;
text-align: left;
}
.english {
font-size: 16px;
}
.meaningSent {
font-size: 16px;
text-align: left;
}
.description {
font-size: 16px;
color: #575757;
}
.image {
margin-top: 20px;
border-left: 3px solid black;
padding-left: 10px;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment