[Add] copy news to ocpf-news
update the content in ocfp-news
This commit is contained in:
parent
2e90998388
commit
529b0fc9dc
199
src/components/ocfp-news/Agenda.vue
Normal file
199
src/components/ocfp-news/Agenda.vue
Normal file
@ -0,0 +1,199 @@
|
||||
<template>
|
||||
<div class="info">
|
||||
<div class="info-container">
|
||||
<!-- 投稿方式 -->
|
||||
<section class="info-section" id="methods">
|
||||
<h1>投稿格式</h1>
|
||||
<article class="info-section__content">
|
||||
<p>
|
||||
除有特別標示會公布的資料外,其餘則只會供審稿委員閱讀。
|
||||
</p>
|
||||
<article class="info-section__content--sub">
|
||||
<h2>投稿格式</h2>
|
||||
<p>
|
||||
各議程類型的投稿格式相同,除特別標示之資訊外,其餘僅供審稿委員於審稿時閱讀。
|
||||
<br>
|
||||
<br>
|
||||
<ul>
|
||||
<li><span /><strong>題目 Title:</strong>必填、公開。請不要超出 20 字。</li>
|
||||
<li><span /><strong>摘要 Abstract:</strong>必填、公開。建議含標點符號 150–250 字,使用於宣傳與網站公告。</li>
|
||||
<li><span /><strong>演講大綱 Outline:</strong>必填,請說明該開放式議程的大綱、如何進行、時間長度規劃。</li>
|
||||
<li><span /><strong>目標受眾 Target
|
||||
Audience:</strong>必填,請說明您期待該議程的目標受眾,為怎麼樣的人。例如:「嚮往成為前端開發者的初學者」、「不知道該不該讀研究所的學生」等。</li>
|
||||
<li><span /><strong>先備知識 Prior Knowledge:</strong>必填、公開。請說明該議程的與會者所需具備的先備知識。例如:「能理解 Python 基礎語法」、「能熟練運用 Class 與 OOP」等。
|
||||
</li>
|
||||
<li><span /><strong>詳細說明
|
||||
Description:</strong>必填。不限字數,請說明這個議程您認為重要的相關細節,以利審稿委員更瞭解您的作品。我們強烈建議您詳細填寫此項,讓審稿委員全面且深入地了解您的稿件,增加入選機率。
|
||||
</li>
|
||||
<li><span /><strong>附件 Attachment:</strong>選填。可以附上程式碼、投影片草稿或任何您認為有助於我們瞭解您的議程的附件。</li>
|
||||
</ul>
|
||||
</p>
|
||||
</article>
|
||||
<article class="info-section__content--sub">
|
||||
|
||||
<h2>個人資料</h2>
|
||||
<p>
|
||||
除了暱稱/姓名被用於宣傳,其餘資訊僅需提供一人作為代表(當稿件同時有多位講者時),供議程組於聯絡時使用。
|
||||
<br>
|
||||
<br>
|
||||
|
||||
<ul>
|
||||
<li><span /><strong>電子郵件 Email:</strong>能讓大會聯絡的電子信箱。(注意:請您在大會的聯絡過程中,維持使用相同信箱。)</li>
|
||||
<li><span /><strong>暱稱/名字 Name:</strong>公開於講者海報及網站的稱呼。</li>
|
||||
<li><span /><strong>手機號碼 Phone:</strong>用於大會聯絡、確認資訊用的電話號碼。</li>
|
||||
<li><span /><strong>其他聯絡方式 Other contact information:</strong>其他任何我們能聯絡您的方式(如 Telegram、住處電話等)。
|
||||
</li>
|
||||
</ul>
|
||||
</p>
|
||||
</article>
|
||||
</article>
|
||||
</section>
|
||||
<!-- 投稿方式 -->
|
||||
<!-- 審稿方式 -->
|
||||
<section class="info-section" id="review">
|
||||
<h1>審稿方式</h1>
|
||||
<article class="info-section__content">
|
||||
<p>
|
||||
審稿委員將針對以下項目進行篩選:
|
||||
<ul>
|
||||
<li><span /><strong>稿件內容:</strong>包含的知識分享、經驗案例、想法觀點是否獨特等。</li>
|
||||
<li><span /><strong>表達能力:</strong>提供的資料是否有條理、文句暢通,提供資料(尤其是稿件的詳細說明)之完整度。我們偏好完整的資料,讓審稿委員更清楚了解演講細節。</li>
|
||||
<li><span /><strong>適合聽眾:</strong>稿件是否適合 SITCON 大多數的與會者討論。</li>
|
||||
</ul>
|
||||
</p>
|
||||
</article>
|
||||
<!-- 審稿方式 -->
|
||||
<!-- 投稿注意事項 -->
|
||||
</section>
|
||||
<section class="info-section" id="precautions">
|
||||
<h1>投稿注意事項</h1>
|
||||
<article class="info-section__content">
|
||||
<p>
|
||||
<ul>
|
||||
<li><span />SITCON 2021 採用 Google Forms 接收投稿。</li>
|
||||
<li><span />議程時間長度以 40 分鐘為原則。</li>
|
||||
<li><span />除了開放式議程外,同一時間將有 3 至 4 軌一般議程同時進行。</li>
|
||||
<li><span />上述審稿方式不考慮稿件內容的技術難度,我們仍以稿件是否能夠吸引人、高品質、適合與會者(即上述篩選方式)為考量。</li>
|
||||
<li><span />為鼓勵投稿,大會提供投稿者一組入場票邀請碼
|
||||
(投稿者有多個投稿亦同,即為一人一組,非一稿一組),可優先報名參與本年會。若您的稿件被接受,屆時可使用講者身分入場,不需要另外報名,並可以將入場票邀請碼贈與他人使用,邀請親朋好友共襄盛舉。講者身分入場,每組可獲得一張講者識別證、一份午餐餐盒與一份講者專屬迎賓禮。
|
||||
</li>
|
||||
<li><span />在截稿之前,投稿者可以隨時使用投稿系統修改已投的稿件。</li>
|
||||
<li><span />SITCON 議程組得與投稿者討論並經同意後,轉換稿件之投稿類型。</li>
|
||||
<li><span />無論投稿有無入選,仍然歡迎於年會當天報名其他議程相關活動!</li>
|
||||
<li><span />凡稿件經接受者,年會將頒予感謝狀以表彰投稿者之熱情付出與貢獻。</li>
|
||||
<li><span />「議程題目」、「摘要」與「先備知識」將放置於官方網站與年會前發行的電子報中。</li>
|
||||
</ul>
|
||||
<br />
|
||||
若有任何問題或投稿建議,請 E-mail 至 SITCON 議程組信箱 session[at]sitcon.org。
|
||||
</p>
|
||||
<article class="info-section__content--sub">
|
||||
|
||||
<h2>錄影與紀錄</h2>
|
||||
<p>
|
||||
所有議程皆會錄影,若不希望被錄影與釋出,可以與議程組聯絡。<br />
|
||||
本屆 SITCON
|
||||
提供入選講者試講及彩排的機會。試講除了讓大會工作人員先行對議程內容、演講習慣有初步了解外,也可以讓講者熟悉現場流程、找出能讓簡報更生動精采的模式。彩排則讓講者熟悉現場設備環境、攝影機位置,並且測試
|
||||
Live
|
||||
Demo 情境。希望講者能夠共同參與試講及彩排,一起使年會議程品質更臻完美。
|
||||
</p>
|
||||
</article>
|
||||
<article class="info-section__content--sub">
|
||||
|
||||
|
||||
<h2>授權</h2>
|
||||
<p>
|
||||
議程錄影將在經過您的同意後,一律以 CC - BY 3.0 授權在 YouTube 釋出。
|
||||
議程相關素材,例如投影片等,將由您自行決定在何處、以何種方式釋出,或選擇不釋出,我們不會干涉。年會後,我們將向您蒐集素材連結,若您選擇釋出,我們會將連結放置在年會官方網站的議程表上。
|
||||
</p>
|
||||
</article>
|
||||
<article class="info-section__content--sub">
|
||||
<h2>試講</h2>
|
||||
<p>
|
||||
試講提供講者在演講前有練習的機會,比照年會時間安排供講者講完整場演講,並有議程組人員提供建議(如簡報、台風等),講者可以自由參加,並自行選擇最合適的場次。若您的稿件確認入選,議程組將與您協調精確時間。
|
||||
</p>
|
||||
<p>
|
||||
所有場次將依報名情況舉辦,預計舉辦北部、中部、南部、東部場等,時間約為四月份,地點另行通知。 補助:依照客運價格標準,補助講者至最近試講場地的全額或部分車馬費。
|
||||
</p>
|
||||
</article>
|
||||
<article class="info-section__content--sub">
|
||||
|
||||
<h2>彩排</h2>
|
||||
<p>
|
||||
<ul>
|
||||
<li><span />日期:2021/05/28(五)。</li>
|
||||
<li><span />場地:使用場地與正式年會相同,細節將於稿件接受後通知。</li>
|
||||
<li><span />時間:一人約 5–10 分鐘。若有 Live Demo 或特殊需求,可提前與議程組安排時間。</li>
|
||||
<li><span />流程:講者操作設備,測試 Live Demo 連結及切換方式,也可以演練部分簡報內容。</li>
|
||||
<li><span />提供設備:與年會當天場地的設備相同,有麥克風、倒數計時器等。</li>
|
||||
</ul>
|
||||
</p>
|
||||
</article>
|
||||
<article class="info-section__content--sub info-section__content--sub-extend">
|
||||
<h2>Q&A</h2>
|
||||
<div class="info-qa">
|
||||
<div class="info-qa__itemBox">
|
||||
<input class="info-qa__itemBox-input" type="checkbox" name="checkbox" id="1">
|
||||
<label class="info-qa__itemBox-title" for="1">
|
||||
<p>我想在開放式議程嘗試 XXX 可以嗎?</p>
|
||||
<span class="info-qa__itemBox-checkmark">
|
||||
<div class="info-qa-icon"></div>
|
||||
</span>
|
||||
</label>
|
||||
<div class="info-qa__itemBox-text">
|
||||
<p>
|
||||
原則上只要是跳脫傳統演講形式,以雙向互動為主的議程進行方式都是可以的,但必須遵守 CoC,且建議議程以知識與想法交流為優先。
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="info-qa__itemBox">
|
||||
<input class="info-qa__itemBox-input" type="checkbox" name="checkbox" id="2">
|
||||
<label class="info-qa__itemBox-title" for="2">
|
||||
<p>先備知識與目標受眾有何不同?</p>
|
||||
<span class="info-qa__itemBox-checkmark">
|
||||
<div class="info-qa-icon"></div>
|
||||
</span>
|
||||
</label>
|
||||
<div class="info-qa__itemBox-text">
|
||||
<p>
|
||||
.....
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="info-qa__itemBox">
|
||||
<input class="info-qa__itemBox-input" type="checkbox" name="checkbox" id="6">
|
||||
<label class="info-qa__itemBox-title" for="6">
|
||||
<p>還有疑問怎麼辦?</p>
|
||||
<span class="info-qa__itemBox-checkmark" type="radio" name="radio" id="6">
|
||||
<div class="info-qa-icon"></div>
|
||||
</span>
|
||||
</label>
|
||||
<div class="info-qa__itemBox-text">
|
||||
<p>
|
||||
歡迎來投稿者小聚與我們聊聊,或寄信至 session[at]sitcon.org 詢問,我們會儘速回應。
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="info-sitcon-img__box">
|
||||
<img src="../../assets/images/CFP/sitcon-img.svg" class="info-sitcon-img">
|
||||
</div>
|
||||
</article>
|
||||
|
||||
</article>
|
||||
<!-- 投稿注意事項 -->
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
|
||||
<script lang="ts">
|
||||
import { Component, Prop, Vue } from 'vue-property-decorator';
|
||||
@Component({})
|
||||
export default class Agenda extends Vue {}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
@import "@/assets/scss/news/agenda";
|
||||
</style>
|
124
src/components/ocfp-news/Header.vue
Normal file
124
src/components/ocfp-news/Header.vue
Normal file
@ -0,0 +1,124 @@
|
||||
<template>
|
||||
<header>
|
||||
<div class="top-bar">
|
||||
<div class="return-wrapper">
|
||||
<a class="shape-wrapper diamond" href="/2021/cfp"
|
||||
><span class="text-wrapper">返回</span></a
|
||||
>
|
||||
</div>
|
||||
<div class="title-wrapper text-center">
|
||||
<img src="~@/assets/images/burnfont/news.svg" class="svg svg-cfp-news" />
|
||||
</div>
|
||||
<div class="contribute-wrapper">
|
||||
<a class="btn-contribute" target="_blank" rel="noopener" href="https://forms.gle/XoXJSD2P8dL8X8s2A">我要投稿</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="cfp-body" :class="(cfp)? 'cfp-body-blue':'cfp-body-gray'">
|
||||
<div class="spot-wrapper" >
|
||||
<h1 class="text-center" v-if="cfp">現正徵稿中<span class="ignore">!</span></h1>
|
||||
<h1 class="text-center" v-else>徵稿已截止 :<span class="ignore">(</span></h1>
|
||||
<!-- TODO counter -->
|
||||
<p class="text-center countdown">
|
||||
距離投稿截止還有
|
||||
<span class="d-inline-block" v-if="cfp">
|
||||
{{ countdown.d }} 天 {{ countdown.h }} 小時 {{ countdown.m }} 分
|
||||
{{ countdown.s }} 秒</span
|
||||
>
|
||||
<span v-else class="d-inline-block">...喔不! 你沒有時間了</span>
|
||||
</p>
|
||||
</div>
|
||||
<div class="time-wrapper">
|
||||
<div class="start-time-wrapper">
|
||||
<h2>投稿開始</h2>
|
||||
<p>2021/01/20(三)</p>
|
||||
</div>
|
||||
<div class="tilde-wrapper">
|
||||
<h2><!-- pseudo element --></h2>
|
||||
<p>~</p>
|
||||
<p></p>
|
||||
</div>
|
||||
|
||||
<div class="end-time-wrapper">
|
||||
<h2>投稿結束</h2>
|
||||
<p>
|
||||
2021/02/22(一)日出<small class="d-inline-block"
|
||||
>(清晨 06:23)</small
|
||||
>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { Component, Prop, Vue } from 'vue-property-decorator';
|
||||
|
||||
const DEAD_LINE = Math.floor(
|
||||
new Date('22 Feb 2021 06:24:00 GMT+8').getTime() / 1000
|
||||
);
|
||||
|
||||
interface Countdown {
|
||||
s: number;
|
||||
m: number;
|
||||
h: number;
|
||||
d: number;
|
||||
}
|
||||
|
||||
@Component({})
|
||||
export default class CfpHeader extends Vue {
|
||||
private timerId!: number;
|
||||
private countdown: Countdown = {
|
||||
s: 0,
|
||||
m: 0,
|
||||
h: 0,
|
||||
d: 0
|
||||
};
|
||||
private cfp: boolean = true;
|
||||
public beforeMount () {
|
||||
this.registerTimer();
|
||||
}
|
||||
|
||||
public unmouted () {
|
||||
this.unregisterTimer();
|
||||
}
|
||||
|
||||
public async createTimer (f: (t: number) => void): Promise<number> {
|
||||
const d = new Date();
|
||||
let t = d.getTime();
|
||||
const rem = 1000 - (t % 1000);
|
||||
|
||||
t = Math.floor(t / 1000);
|
||||
let downcount = DEAD_LINE - t - 1;
|
||||
this.onTick(downcount);
|
||||
const id = setInterval(() => {
|
||||
f(--downcount);
|
||||
}, 1000);
|
||||
return id;
|
||||
}
|
||||
|
||||
private async onTick (t: number) {
|
||||
if (t<0) this.cfp = false;
|
||||
this.countdown.s = t % 60;
|
||||
t = Math.floor(t / 60);
|
||||
this.countdown.m = t % 60;
|
||||
t = Math.floor(t / 60);
|
||||
this.countdown.h = t % 24;
|
||||
t = Math.floor(t / 24);
|
||||
this.countdown.d = t;
|
||||
}
|
||||
|
||||
private async registerTimer () {
|
||||
this.timerId = await this.createTimer(this.onTick);
|
||||
}
|
||||
|
||||
private unregisterTimer () {
|
||||
clearInterval(this.timerId);
|
||||
}
|
||||
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
@import '@/assets/scss/news/header'
|
||||
</style>
|
116
src/components/ocfp-news/Navbar.vue
Normal file
116
src/components/ocfp-news/Navbar.vue
Normal file
@ -0,0 +1,116 @@
|
||||
<template>
|
||||
<nav id="news-nav" :class="{ fixed: (isNavbarFixed || isMobileView), returning: isNavbarReturning }">
|
||||
<div
|
||||
class="news-nav"
|
||||
:class="{ animating: isNavbarAnimating }"
|
||||
v-show="!isMobileView || navVisible"
|
||||
v-scrollspy="{ selectors: navbarItems }"
|
||||
>
|
||||
<a class="news-nav-item" href="#schedule">重要時程</a>
|
||||
<a class="news-nav-item" href="#example">投稿主題範例</a>
|
||||
<a class="news-nav-item" href="#code-of-conduct">Code of Conduct</a>
|
||||
<a class="news-nav-item" href="#info-section">議程種類</a>
|
||||
<a class="news-nav-item" href="#process">流程</a>
|
||||
<a class="news-nav-item" href="#methods">投稿方式</a>
|
||||
<a class="news-nav-item" href="#review">審稿方式</a>
|
||||
<a class="news-nav-item" href="#precautions">投稿注意事項</a>
|
||||
<a class="news-nav-contribute-button" target="_blank" rel="noopener" href="https://forms.gle/XoXJSD2P8dL8X8s2A" v-show="!isMobileView">我要投稿</a>
|
||||
<button class="news-nav-button" @click="(e)=>navVisible=!navVisible" v-show="isMobileView">▲</button>
|
||||
</div>
|
||||
<button v-show="!navVisible && isMobileView" class="nav-control-button" @click="(e)=>navVisible=!navVisible">
|
||||
<p>▲</p>
|
||||
<p>▼</p>
|
||||
</button>
|
||||
</nav>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { Component, Prop, Vue } from 'vue-property-decorator';
|
||||
import ScrollSpyDirective from './ScrollSpyDirective';
|
||||
|
||||
@Component({
|
||||
directives: {
|
||||
scrollspy: ScrollSpyDirective
|
||||
}
|
||||
})
|
||||
export default class Navbar extends Vue {
|
||||
private isMobileView: boolean = false;
|
||||
private isNavbarFixed: boolean = false;
|
||||
private isNavbarAnimating: boolean = false;
|
||||
private isNavbarReturning: boolean = false;
|
||||
private navVisible: boolean = false;
|
||||
private navbarItems: string[] = [
|
||||
'#schedule',
|
||||
'#example',
|
||||
'#code-of-conduct',
|
||||
'#info-section',
|
||||
'#process',
|
||||
'#methods',
|
||||
'#review',
|
||||
'#precautions'
|
||||
];
|
||||
|
||||
public created () {
|
||||
const query: string = '(max-width: 1024px)';
|
||||
const mq: MediaQueryList = window.matchMedia(query);
|
||||
if (mq.addEventListener) {
|
||||
mq.addEventListener('change', this.matchMediaCallback);
|
||||
} else {
|
||||
// for sad safari
|
||||
mq.addListener(this.matchMediaCallback);
|
||||
}
|
||||
// check first
|
||||
this.matchMediaCallback(mq);
|
||||
}
|
||||
|
||||
public mounted () {
|
||||
// observe header: header appears => no fix; header disappears => fix.
|
||||
const fixObserver: IntersectionObserver = new IntersectionObserver((entries, observer) => {
|
||||
entries.forEach((entry) => {
|
||||
// no animation for mobile
|
||||
if (!this.isMobileView) {
|
||||
// only show animation if fix status has changed
|
||||
if (!entry.isIntersecting !== this.isNavbarFixed) {
|
||||
if (!entry.isIntersecting) {
|
||||
this.isNavbarFixed = true;
|
||||
} else {
|
||||
this.isNavbarFixed = false;
|
||||
this.isNavbarReturning = true;
|
||||
}
|
||||
|
||||
this.isNavbarAnimating = true;
|
||||
}
|
||||
}
|
||||
});
|
||||
}, { rootMargin: '25px 0px 0px 0px', threshold: 0 });
|
||||
this.$nextTick().then(() => {
|
||||
fixObserver.observe(document.querySelector('#news-header') as Element);
|
||||
|
||||
document.querySelector('.news-nav')?.addEventListener('animationend', (ev) => {
|
||||
if (!this.isNavbarFixed) {
|
||||
this.isNavbarReturning = false;
|
||||
}
|
||||
this.isNavbarAnimating = false;
|
||||
});
|
||||
|
||||
if (location.hash) {
|
||||
const hash = location.hash;
|
||||
// scroll to anchor
|
||||
// value should be changed to scroll, so set to empty string first.
|
||||
location.hash = '';
|
||||
location.hash = hash;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private matchMediaCallback (ev: (MediaQueryList | MediaQueryListEvent)) {
|
||||
this.isMobileView = ev.matches;
|
||||
// alaways disable navbar while view changing
|
||||
this.navVisible = false;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import '@/assets/scss/news/navbar';
|
||||
</style>
|
67
src/components/ocfp-news/Schedule.vue
Normal file
67
src/components/ocfp-news/Schedule.vue
Normal file
@ -0,0 +1,67 @@
|
||||
<template>
|
||||
<div>
|
||||
<Navbar />
|
||||
<!-- 重要時程 -->
|
||||
<section id="schedule">
|
||||
<h1>重要時程</h1>
|
||||
<ul>
|
||||
<li>2020/04/06(二)日出(早上 06:41)投稿截止</li>
|
||||
<li>3 月下旬第二階段補充資料截止收取</li>
|
||||
<li>預計於五月初公佈完整議程</li>
|
||||
<li>2021/05/29(六)SITCON 2021 年會</li>
|
||||
</ul>
|
||||
</section>
|
||||
<!-- 重要時程 -->
|
||||
<!-- 投稿主題範例 -->
|
||||
<section id="example">
|
||||
<article id="theme-example">
|
||||
<h1>投稿主題</h1>
|
||||
<p>延續著去年的熱潮,開放式議程將於 SITCON 2021 舉辦,期待藉由主講者及會眾的雙向資訊傳遞,激盪出熱烈的討論及更多的觀點。在開放式議程中,您可以舉辦一場精彩的議題探討,也可以集思廣益,解決學生在資訊界可能碰到的困難。任何形式的議程,都可以於開放式議程中實現。</p>
|
||||
<p>SITCON 作為學生展現自己的舞台,我們期待以學生為主體的投稿,以下提供幾種開放式議程形式範例 :</p>
|
||||
<!-- there is a object arr named 'themeExample', each object have two value ie. title and content -->
|
||||
<div class="theme container">
|
||||
<Topic v-for="theme in themeExample" :topic="theme.title" :description="theme.context" :key="theme.title" />
|
||||
</div>
|
||||
</article>
|
||||
<p>
|
||||
除了以上範例,我們也非常歡迎其他形式的議程。
|
||||
</p>
|
||||
</section>
|
||||
<!-- 投稿主題範例 -->
|
||||
<!-- Code of Conduct -->
|
||||
<section id="code-of-conduct">
|
||||
<h1>Code of Conduct</h1>
|
||||
<p>SITCON 歡迎不同身分、來自不同背景的與會者,也非常鼓勵女性、性少數與多元背景的參與者。為了讓大家都能愉快的參加 SITCON,我們要求所有參與者閱讀年會的<a href="https://sitcon.org/code-of-conduct/" target="_blank" rel="noopener"><u>行為守則(Code of Conduct)</u></a>,共同創造一個友善的環境。</p>
|
||||
</section>
|
||||
<!-- Code of Conduct -->
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { Component, Prop, Vue } from 'vue-property-decorator';
|
||||
import AgendaCard from './AgendaCard.vue';
|
||||
import Topic from './Topic.vue';
|
||||
import Navbar from './Navbar.vue';
|
||||
|
||||
// import data
|
||||
import themeExample from '../../../template/themeExample.cfp';
|
||||
import espresso from '../../../template/espresso.cfp';
|
||||
import presentation from '../../../template/presentation.cfp';
|
||||
|
||||
@Component({
|
||||
components: {
|
||||
AgendaCard,
|
||||
Topic,
|
||||
Navbar
|
||||
}
|
||||
})
|
||||
export default class Schedule extends Vue {
|
||||
private themeExample = themeExample;
|
||||
private espresso = espresso;
|
||||
private presentation = presentation;
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
@import '@/assets/scss/news/schedule';
|
||||
</style>
|
37
src/components/ocfp-news/ScrollSpyDirective.ts
Normal file
37
src/components/ocfp-news/ScrollSpyDirective.ts
Normal file
@ -0,0 +1,37 @@
|
||||
import Vue, { DirectiveOptions, VNode, VNodeDirective } from 'vue';
|
||||
|
||||
let selectors!: string[];
|
||||
let observer!: IntersectionObserver;
|
||||
|
||||
const ScrollSpyDirective: DirectiveOptions = {
|
||||
inserted (el: Element, binding: VNodeDirective, vnode: VNode) {
|
||||
selectors = binding.value.selectors;
|
||||
|
||||
// highlight first element
|
||||
el.querySelector(`[href="${selectors[0] || ''}"]`)?.classList.toggle('active', true);
|
||||
|
||||
const config = {
|
||||
rootMargin: '-5% 0px -85% 0px',
|
||||
threshold: 0
|
||||
};
|
||||
|
||||
observer = new IntersectionObserver((entries, observer) => {
|
||||
entries.forEach((entry) => {
|
||||
if (entry.isIntersecting) {
|
||||
selectors.forEach((selector: string) => {
|
||||
el.querySelector(`[href="${selector}"`)?.classList.toggle('active', selector === `#${entry.target.id}`);
|
||||
});
|
||||
}
|
||||
});
|
||||
}, config);
|
||||
|
||||
selectors.forEach((selector: string) => {
|
||||
observer.observe(document.querySelector(selector) as Element);
|
||||
});
|
||||
},
|
||||
unbind () {
|
||||
observer.disconnect();
|
||||
}
|
||||
};
|
||||
|
||||
export default ScrollSpyDirective;
|
25
src/components/ocfp-news/Topic.vue
Normal file
25
src/components/ocfp-news/Topic.vue
Normal file
@ -0,0 +1,25 @@
|
||||
<template>
|
||||
<div class="topic">
|
||||
<h3 class="title" v-html="title"></h3>
|
||||
<div class="divider"></div>
|
||||
<p class="description">{{ description }}</p>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { Component, Prop, Vue } from 'vue-property-decorator';
|
||||
|
||||
@Component
|
||||
export default class Topic extends Vue {
|
||||
@Prop({ required: true }) private topic!: string;
|
||||
@Prop({ required: true }) private description!: string;
|
||||
|
||||
get title () {
|
||||
return this.topic.replace(/(:|?)/, '$1<br data-delimiter="$1">');
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
@import '@/assets/scss/news/topic';
|
||||
</style>
|
26
src/pages/OCFP.vue
Normal file
26
src/pages/OCFP.vue
Normal file
@ -0,0 +1,26 @@
|
||||
<template>
|
||||
<div class="news">
|
||||
<NewsHeader id="news-header" />
|
||||
<Schedule id="news-schedule" />
|
||||
<Agenda id="news-agenda" />
|
||||
<!-- <Footer></Footer> should be put at App.vue (?) -->
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { Component, Prop, Vue } from 'vue-property-decorator';
|
||||
import NewsHeader from '@/components/ocfp-news/Header.vue';
|
||||
import Schedule from '@/components/ocfp-news/Schedule.vue';
|
||||
import Agenda from '@/components/ocfp-news/Agenda.vue';
|
||||
|
||||
@Component({
|
||||
components: {
|
||||
NewsHeader,
|
||||
Schedule,
|
||||
Agenda
|
||||
}
|
||||
})
|
||||
export default class News extends Vue {
|
||||
@Prop() private msg!: string;
|
||||
}
|
||||
</script>
|
@ -3,6 +3,7 @@ import VueRouter, { RouteConfig } from 'vue-router';
|
||||
// components
|
||||
import CFP from '../pages/CFP.vue';
|
||||
import News from '../pages/News.vue';
|
||||
import OCFP from '../pages/OCFP.vue';
|
||||
|
||||
Vue.use(VueRouter);
|
||||
|
||||
@ -25,6 +26,14 @@ export const routes: RouteConfig[] = [
|
||||
menuItem: false
|
||||
}
|
||||
},
|
||||
{
|
||||
path: '/cfp/ocfp-news',
|
||||
name: 'ocfp-news',
|
||||
component: OCFP,
|
||||
meta: {
|
||||
menuItem: false
|
||||
}
|
||||
},
|
||||
{
|
||||
path: '/cfp/news',
|
||||
name: 'news',
|
||||
|
Loading…
x
Reference in New Issue
Block a user