[Add] copy news to ocpf-news

update the content in ocfp-news
This commit is contained in:
mysper 2021-03-03 14:59:23 +08:00
parent 2e90998388
commit 529b0fc9dc
8 changed files with 603 additions and 0 deletions

View 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>必填公開建議含標點符號 150250 使用於宣傳與網站公告</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 />時間一人約 510 分鐘若有 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>

View 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"
>清晨 0623</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>

View 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">&#9650;</button>
</div>
<button v-show="!navVisible && isMobileView" class="nav-control-button" @click="(e)=>navVisible=!navVisible">
<p>&#9650;</p>
<p>&#9660;</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>

View 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/29SITCON 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>

View 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;

View 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
View 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>

View File

@ -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',