Tailwind, side barr, add new component button, layour of route

This commit is contained in:
Rotimi-Best
2020-12-26 02:22:37 +02:00
parent b700f6bb07
commit ba06a0001a
27 changed files with 1753 additions and 636 deletions
+1 -1
View File
@@ -85,7 +85,7 @@ This is the heart of your Sapper app. There are two kinds of routes — *pages*,
There are three simple rules for naming the files that define your routes: There are three simple rules for naming the files that define your routes:
* A file called `src/routes/about.svelte` corresponds to the `/about` route. A file called `src/routes/blog/[slug].svelte` corresponds to the `/blog/:slug` route, in which case `params.slug` is available to the route * A file called `src/routes/about.svelte` corresponds to the `/about` route. A file called `src/routes/blog/[id].svelte` corresponds to the `/blog/:id` route, in which case `params.id` is available to the route
* The file `src/routes/index.svelte` (or `src/routes/index.js`) corresponds to the root of your app. `src/routes/about/index.svelte` is treated the same as `src/routes/about.svelte`. * The file `src/routes/index.svelte` (or `src/routes/index.js`) corresponds to the root of your app. `src/routes/about/index.svelte` is treated the same as `src/routes/about.svelte`.
* Files and directories with a leading underscore do *not* create routes. This allows you to colocate helper modules and components with the routes that depend on them — for example you could have a file called `src/routes/_helpers/datetime.js` and it would *not* create a `/_helpers/datetime` route. * Files and directories with a leading underscore do *not* create routes. This allows you to colocate helper modules and components with the routes that depend on them — for example you could have a file called `src/routes/_helpers/datetime.js` and it would *not* create a `/_helpers/datetime` route.
+13
View File
@@ -0,0 +1,13 @@
const fs = require('fs');
const type = process.argv[2];
const pkg = require('../package_template.json');
for (const key in pkg['merge-configs'][type]) {
Object.assign(pkg[key], pkg['merge-configs'][type][key]);
}
delete pkg['merge-configs'];
fs.writeFileSync(
__dirname + '/../package.json',
JSON.stringify(pkg, null, ' ') + '\n'
);
+19
View File
@@ -0,0 +1,19 @@
#!/bin/bash
cd "$(dirname "$0")"
if [ "$CI" ]; then
(umask 0077; echo "$SSH_KEY" > ~/ssh_key; echo "$SSH_KEY_ROLLUP" > ~/ssh_key_rollup; echo "$SSH_KEY_WEBPACK" > ~/ssh_key_webpack)
git config user.email 'noreply@svelte.dev'
git config user.name '[bot]'
fi
# branch names
ROLLUP=rollup
WEBPACK=webpack
./create-branches.sh $ROLLUP $WEBPACK
# force push rollup and webpack branches and repos
GIT_SSH_COMMAND='ssh -o StrictHostKeyChecking=accept-new -i ~/ssh_key' git push git@github.com:sveltejs/sapper-template.git $ROLLUP $WEBPACK -f
GIT_SSH_COMMAND='ssh -o StrictHostKeyChecking=accept-new -i ~/ssh_key_rollup' git push git@github.com:sveltejs/sapper-template-rollup.git $ROLLUP:master -f
GIT_SSH_COMMAND='ssh -o StrictHostKeyChecking=accept-new -i ~/ssh_key_webpack' git push git@github.com:sveltejs/sapper-template-webpack.git $WEBPACK:master -f
+25
View File
@@ -0,0 +1,25 @@
#!/bin/bash
cd "$(dirname "$0")"/..
HEAD=$(git rev-parse HEAD)
ROLLUP=${1:-rollup}
WEBPACK=${2:-webpack}
echo "Creating $ROLLUP and $WEBPACK branches from $REV"
# create the $ROLLUP branch off the current HEAD
git symbolic-ref HEAD refs/heads/$ROLLUP
git reset $HEAD --hard
node _template/build-pkg.js rollup
git rm -r --cached .github _template package_template.json webpack.config.js
git add package.json
git commit -m 'Sapper template for Rollup'
# create the $WEBPACK branch off the current HEAD
git symbolic-ref HEAD refs/heads/$WEBPACK
git reset $HEAD --hard
node _template/build-pkg.js webpack
git rm -r --cached .github _template package_template.json rollup.config.js
git add package.json
git commit -m 'Sapper template for webpack'
+872 -33
View File
File diff suppressed because it is too large Load Diff
+8 -5
View File
@@ -1,6 +1,6 @@
{ {
"name": "TODO", "name": "Unidiscuss",
"description": "TODO", "description": "Unidiscuss",
"version": "0.0.1", "version": "0.0.1",
"scripts": { "scripts": {
"dev": "sapper dev", "dev": "sapper dev",
@@ -23,12 +23,15 @@
"@rollup/plugin-commonjs": "^14.0.0", "@rollup/plugin-commonjs": "^14.0.0",
"@rollup/plugin-node-resolve": "^8.0.0", "@rollup/plugin-node-resolve": "^8.0.0",
"@rollup/plugin-replace": "^2.2.0", "@rollup/plugin-replace": "^2.2.0",
"@rollup/plugin-url": "^5.0.0",
"carbon-icons-svelte": "^10.21.0", "carbon-icons-svelte": "^10.21.0",
"postcss": "^8.0.9",
"postcss-load-config": "^2.1.0",
"rollup": "^2.3.4", "rollup": "^2.3.4",
"rollup-plugin-svelte": "^7.0.0", "rollup-plugin-svelte": "^6.0.0",
"rollup-plugin-terser": "^7.0.0", "rollup-plugin-terser": "^7.0.0",
"sapper": "^0.28.0", "sapper": "^0.28.0",
"svelte": "^3.17.3" "svelte": "^3.17.3",
"svelte-preprocess": "^4.3.0",
"tailwindcss": "^1.8.10"
} }
} }
+3
View File
@@ -0,0 +1,3 @@
module.exports = {
plugins: [require('tailwindcss')],
};
+57 -55
View File
@@ -1,72 +1,79 @@
import path from 'path'; import resolve from "@rollup/plugin-node-resolve";
import resolve from '@rollup/plugin-node-resolve'; import replace from "@rollup/plugin-replace";
import replace from '@rollup/plugin-replace'; import commonjs from "@rollup/plugin-commonjs";
import commonjs from '@rollup/plugin-commonjs'; import svelte from "rollup-plugin-svelte";
import url from '@rollup/plugin-url'; import babel from "@rollup/plugin-babel";
import svelte from 'rollup-plugin-svelte'; import { terser } from "rollup-plugin-terser";
import babel from '@rollup/plugin-babel'; import config from "sapper/config/rollup.js";
import { terser } from 'rollup-plugin-terser'; import sveltePreprocess from "svelte-preprocess";
import config from 'sapper/config/rollup.js';
import pkg from './package.json'; import pkg from "./package.json";
const mode = process.env.NODE_ENV; const mode = process.env.NODE_ENV;
const dev = mode === 'development'; const dev = mode === "development";
const legacy = !!process.env.SAPPER_LEGACY_BUILD; const legacy = !!process.env.SAPPER_LEGACY_BUILD;
const onwarn = (warning, onwarn) => const onwarn = (warning, onwarn) =>
(warning.code === 'MISSING_EXPORT' && /'preload'/.test(warning.message)) || (warning.code === "MISSING_EXPORT" && /'preload'/.test(warning.message)) ||
(warning.code === 'CIRCULAR_DEPENDENCY' && /[/\\]@sapper[/\\]/.test(warning.message)) || (warning.code === "CIRCULAR_DEPENDENCY" &&
/[/\\]@sapper[/\\]/.test(warning.message)) ||
onwarn(warning); onwarn(warning);
const preprocess = sveltePreprocess({ postcss: true });
export default { export default {
client: { client: {
input: config.client.input(), input: config.client.input(),
output: config.client.output(), output: config.client.output(),
plugins: [ plugins: [
replace({ replace({
'process.browser': true, "process.browser": true,
'process.env.NODE_ENV': JSON.stringify(mode) "process.env.NODE_ENV": JSON.stringify(mode)
}), }),
svelte({ svelte({
compilerOptions: { preprocess,
dev, dev,
hydratable: true hydratable: true,
} emitCss: true
}),
url({
sourceDir: path.resolve(__dirname, 'src/node_modules/images'),
publicPath: '/client/'
}), }),
resolve({ resolve({
browser: true, browser: true,
dedupe: ['svelte'] dedupe: ["svelte"]
}), }),
commonjs(), commonjs(),
legacy && babel({ legacy &&
extensions: ['.js', '.mjs', '.html', '.svelte'], babel({
babelHelpers: 'runtime', extensions: [".js", ".mjs", ".html", ".svelte"],
exclude: ['node_modules/@babel/**'], babelHelpers: "runtime",
exclude: ["node_modules/@babel/**"],
presets: [ presets: [
['@babel/preset-env', { [
targets: '> 0.25%, not dead' "@babel/preset-env",
}] {
targets: "> 0.25%, not dead"
}
]
], ],
plugins: [ plugins: [
'@babel/plugin-syntax-dynamic-import', "@babel/plugin-syntax-dynamic-import",
['@babel/plugin-transform-runtime', { [
"@babel/plugin-transform-runtime",
{
useESModules: true useESModules: true
}] }
]
] ]
}), }),
!dev && terser({ !dev &&
terser({
module: true module: true
}) })
], ],
preserveEntrySignatures: false, preserveEntrySignatures: false,
onwarn, onwarn
}, },
server: { server: {
@@ -74,31 +81,26 @@ export default {
output: config.server.output(), output: config.server.output(),
plugins: [ plugins: [
replace({ replace({
'process.browser': false, "process.browser": false,
'process.env.NODE_ENV': JSON.stringify(mode) "process.env.NODE_ENV": JSON.stringify(mode)
}), }),
svelte({ svelte({
compilerOptions: { preprocess,
dev, generate: "ssr",
generate: 'ssr', hydratable: true,
hydratable: true dev
},
emitCss: false
}),
url({
sourceDir: path.resolve(__dirname, 'src/node_modules/images'),
publicPath: '/client/',
emitFiles: false // already emitted by client build
}), }),
resolve({ resolve({
dedupe: ['svelte'] dedupe: ["svelte"]
}), }),
commonjs() commonjs()
], ],
external: Object.keys(pkg.dependencies).concat(require('module').builtinModules), external: Object.keys(pkg.dependencies).concat(
require("module").builtinModules
),
preserveEntrySignatures: 'strict', preserveEntrySignatures: "strict",
onwarn, onwarn
}, },
serviceworker: { serviceworker: {
@@ -107,14 +109,14 @@ export default {
plugins: [ plugins: [
resolve(), resolve(),
replace({ replace({
'process.browser': true, "process.browser": true,
'process.env.NODE_ENV': JSON.stringify(mode) "process.env.NODE_ENV": JSON.stringify(mode)
}), }),
commonjs(), commonjs(),
!dev && terser() !dev && terser()
], ],
preserveEntrySignatures: false, preserveEntrySignatures: false,
onwarn, onwarn
} }
}; };
+106 -122
View File
@@ -5,27 +5,25 @@
*/ */
// @ts-check // @ts-check
const fs = require('fs'); const fs = require("fs");
const path = require('path'); const path = require("path");
const { argv } = require('process'); const { argv } = require("process");
const projectRoot = argv[2] || path.join(__dirname, '..'); const projectRoot = argv[2] || path.join(__dirname, "..");
const isRollup = fs.existsSync(path.join(projectRoot, "rollup.config.js"));
function warn(message) { function warn(message) {
console.warn('Warning: ' + message); console.warn("Warning: " + message);
} }
function replaceInFile(fileName, replacements) { function replaceInFile(fileName, replacements) {
if (fs.existsSync(fileName)) { if (fs.existsSync(fileName)) {
let contents = fs.readFileSync(fileName, 'utf8'); let contents = fs.readFileSync(fileName, "utf8");
let hadUpdates = false; let hadUpdates = false;
replacements.forEach(([from, to]) => { replacements.forEach(([from, to]) => {
const newContents = contents.replace(from, to); const newContents = contents.replace(from, to);
const isAlreadyApplied = typeof to !== 'string' || contents.includes(to); const isAlreadyApplied = typeof to !== "string" || contents.includes(to);
if (newContents !== contents) { if (newContents !== contents) {
contents = newContents; contents = newContents;
@@ -47,34 +45,36 @@ function replaceInFile(fileName, replacements) {
function createFile(fileName, contents) { function createFile(fileName, contents) {
if (fs.existsSync(fileName)) { if (fs.existsSync(fileName)) {
warn(`Wanted to create ${fileName}, but it already existed. Leaving existing file.`); warn(
`Wanted to create ${fileName}, but it already existed. Leaving existing file.`
);
} else { } else {
fs.writeFileSync(fileName, contents); fs.writeFileSync(fileName, contents);
} }
} }
function addDepsToPackageJson() { function addDepsToPackageJson() {
const pkgJSONPath = path.join(projectRoot, 'package.json'); const pkgJSONPath = path.join(projectRoot, "package.json");
const packageJSON = JSON.parse(fs.readFileSync(pkgJSONPath, 'utf8')); const packageJSON = JSON.parse(fs.readFileSync(pkgJSONPath, "utf8"));
packageJSON.devDependencies = Object.assign(packageJSON.devDependencies, { packageJSON.devDependencies = Object.assign(packageJSON.devDependencies, {
...(isRollup ? { '@rollup/plugin-typescript': '^6.0.0' } : { 'ts-loader': '^8.0.4' }), "@rollup/plugin-typescript": "^6.0.0",
'@tsconfig/svelte': '^1.0.10', "@tsconfig/svelte": "^1.0.10",
'@types/compression': '^1.7.0', "@types/compression": "^1.7.0",
'@types/node': '^14.11.1', "@types/node": "^14.11.1",
'@types/polka': '^0.5.1', "@types/polka": "^0.5.1",
'svelte-check': '^1.0.46', "svelte-check": "^1.0.46",
'svelte-preprocess': '^4.3.0', "svelte-preprocess": "^4.3.0",
tslib: '^2.0.1', tslib: "^2.0.1",
typescript: '^4.0.3' typescript: "^4.0.3"
}); });
// Add script for checking // Add script for checking
packageJSON.scripts = Object.assign(packageJSON.scripts, { packageJSON.scripts = Object.assign(packageJSON.scripts, {
validate: 'svelte-check --ignore src/node_modules/@sapper' validate: "svelte-check --ignore src/node_modules/@sapper"
}); });
// Write the package JSON // Write the package JSON
fs.writeFileSync(pkgJSONPath, JSON.stringify(packageJSON, null, ' ')); fs.writeFileSync(pkgJSONPath, JSON.stringify(packageJSON, null, " "));
} }
function changeJsExtensionToTs(dir) { function changeJsExtensionToTs(dir) {
@@ -83,16 +83,28 @@ function changeJsExtensionToTs(dir) {
for (let i = 0; i < elements.length; i++) { for (let i = 0; i < elements.length; i++) {
if (elements[i].isDirectory()) { if (elements[i].isDirectory()) {
changeJsExtensionToTs(path.join(dir, elements[i].name)); changeJsExtensionToTs(path.join(dir, elements[i].name));
} else if (elements[i].name.match(/^[^_]((?!json).)*js$/)) { } else if (elements[i].name.match(/^((?!json).)*js$/)) {
fs.renameSync(path.join(dir, elements[i].name), path.join(dir, elements[i].name).replace('.js', '.ts')); fs.renameSync(
path.join(dir, elements[i].name),
path.join(dir, elements[i].name).replace(".js", ".ts")
);
} }
} }
} }
function updateSingleSvelteFile({ view, vars, contextModule }) { function updateSingleSvelteFile({ view, vars, contextModule }) {
replaceInFile(path.join(projectRoot, 'src', `${view}.svelte`), [ replaceInFile(path.join(projectRoot, "src", `${view}.svelte`), [
[/(?:<script)(( .*?)*?)>/gm, (m, attrs) => `<script${attrs}${!attrs.includes('lang="ts"') ? ' lang="ts"' : ''}>`], [
...(vars ? vars.map(({ name, type }) => [`export let ${name};`, `export let ${name}: ${type};`]) : []), /(?:<script)(( .*?)*?)>/gm,
(m, attrs) =>
`<script${attrs}${!attrs.includes('lang="ts"') ? ' lang="ts"' : ""}>`
],
...(vars
? vars.map(({ name, type }) => [
`export let ${name};`,
`export let ${name}: ${type};`
])
: []),
...(contextModule ? contextModule.map(({ js, ts }) => [js, ts]) : []) ...(contextModule ? contextModule.map(({ js, ts }) => [js, ts]) : [])
]); ]);
} }
@@ -101,132 +113,109 @@ function updateSingleSvelteFile({ view, vars, contextModule }) {
function updateSvelteFiles() { function updateSvelteFiles() {
[ [
{ {
view: 'components/Nav', view: "components/Nav",
vars: [{ name: 'segment', type: 'string' }] vars: [{ name: "segment", type: "string" }]
}, },
{ {
view: 'routes/_layout', view: "routes/_layout",
vars: [{ name: 'segment', type: 'string' }] vars: [{ name: "segment", type: "string" }]
}, },
{ {
view: 'routes/_error', view: "routes/_error",
vars: [ vars: [
{ name: 'status', type: 'number' }, { name: "status", type: "number" },
{ name: 'error', type: 'Error' } { name: "error", type: "Error" }
] ]
}, },
{ {
view: 'routes/blog/index', view: "routes/blog/index",
vars: [{ name: 'posts', type: '{ slug: string; title: string, html: any }[]' }], vars: [
{ name: "posts", type: "{ id: string; title: string, html: any }[]" }
],
contextModule: [ contextModule: [
{ {
js: '.then(r => r.json())', js: ".then(r => r.json())",
ts: '.then((r: { json: () => any; }) => r.json())' ts: ".then((r: { json: () => any; }) => r.json())"
}, },
{ {
js: '.then(posts => {', js: ".then(posts => {",
ts: '.then((posts: { slug: string; title: string, html: any }[]) => {' ts: ".then((posts: { id: string; title: string, html: any }[]) => {"
} }
] ]
}, },
{ {
view: 'routes/blog/[slug]', view: "routes/blog/[id]",
vars: [{ name: 'post', type: '{ slug: string; title: string, html: any }' }] vars: [
{ name: "post", type: "{ id: string; title: string, html: any }" }
]
} }
].forEach(updateSingleSvelteFile); ].forEach(updateSingleSvelteFile);
} }
function updateRollupConfig() { function updateRollupConfig() {
// Edit rollup config // Edit rollup config
replaceInFile(path.join(projectRoot, 'rollup.config.js'), [ replaceInFile(path.join(projectRoot, "rollup.config.js"), [
// Edit imports // Edit imports
[ [
/'rollup-plugin-terser';\n(?!import sveltePreprocess)/, /'rollup-plugin-terser';\n(?!import sveltePreprocess)/,
`'rollup-plugin-terser'; `'rollup-plugin-terser';
import sveltePreprocess from 'svelte-preprocess'; import sveltePreprocess from 'svelte-preprocess';
import typescript from '@rollup/plugin-typescript'; import typescript from '@rollup/plugin-typescript';`
`
], ],
// Edit inputs // Edit inputs
[ [
/(?<!THIS_IS_UNDEFINED[^\n]*\n\s*)onwarn\(warning\);/, /(?<!THIS_IS_UNDEFINED[^\n]*\n\s*)onwarn\(warning\);/,
`(warning.code === 'THIS_IS_UNDEFINED') ||\n\tonwarn(warning);` `(warning.code === 'THIS_IS_UNDEFINED') ||\n\tonwarn(warning);`
], ],
[/input: config.client.input\(\)(?!\.replace)/, `input: config.client.input().replace(/\\.js$/, '.ts')`], [
/input: config.client.input\(\)(?!\.replace)/,
`input: config.client.input().replace(/\.js$/, '.ts')`
],
[ [
/input: config.server.input\(\)(?!\.replace)/, /input: config.server.input\(\)(?!\.replace)/,
`input: { server: config.server.input().server.replace(/\\.js$/, ".ts") }` `input: { server: config.server.input().server.replace(/\.js$/, ".ts") }`
], ],
[ [
/input: config.serviceworker.input\(\)(?!\.replace)/, /input: config.serviceworker.input\(\)(?!\.replace)/,
`input: config.serviceworker.input().replace(/\\.js$/, '.ts')` `input: config.serviceworker.input().replace(/\.js$/, '.ts')`
],
// Add preprocess
[/compilerOptions/g, 'preprocess: sveltePreprocess(),\n\t\t\t\tcompilerOptions'],
// Add TypeScript
[/commonjs\(\)(?!,\n\s*typescript)/g, 'commonjs(),\n\t\t\ttypescript({ sourceMap: dev })']
]);
}
function updateWebpackConfig() {
// Edit webpack config
replaceInFile(path.join(projectRoot, 'webpack.config.js'), [
// Edit imports
[
/require\('webpack-modules'\);\n(?!const sveltePreprocess)/,
`require('webpack-modules');\nconst sveltePreprocess = require('svelte-preprocess');\n`
],
// Edit extensions
[
/\['\.mjs', '\.js', '\.json', '\.svelte', '\.html'\]/,
`['.mjs', '.js', '.ts', '.json', '.svelte', '.html']`
],
// Edit entries
[
/entry: config\.client\.entry\(\)/,
`entry: { main: config.client.entry().main.replace(/\\.js$/, '.ts') }`
],
[
/entry: config\.server\.entry\(\)/,
`entry: { server: config.server.entry().server.replace(/\\.js$/, '.ts') }`
],
[
/entry: config\.serviceworker\.entry\(\)/,
`entry: { 'service-worker': config.serviceworker.entry()['service-worker'].replace(/\\.js$/, '.ts') }`
], ],
// Add preprocess to the svelte config, this is tricky because there's no easy signifier. // Add preprocess to the svelte config, this is tricky because there's no easy signifier.
// Instead we look for 'hydratable: true,' // Instead we look for 'hydratable: true,'
[ [
/hydratable: true(?!,\n\s*preprocess)/g, /hydratable: true(?!,\n\s*preprocess)/g,
'hydratable: true,\n\t\t\t\t\t\t\tpreprocess: sveltePreprocess()' "hydratable: true,\n\t\t\t\tpreprocess: sveltePreprocess()"
], ],
// Add TypeScript rules for client and server // Add TypeScript
[ [
/module: {\n\s*rules: \[\n\s*(?!{\n\s*test: \/\\\.ts\$\/)/g, /commonjs\(\)(?!,\n\s*typescript)/g,
`module: {\n\t\t\trules: [\n\t\t\t\t{\n\t\t\t\t\ttest: /\\.ts$/,\n\t\t\t\t\tloader: 'ts-loader'\n\t\t\t\t},\n\t\t\t\t` "commonjs(),\n\t\t\ttypescript({ sourceMap: dev })"
],
// Add TypeScript rules for serviceworker
[
/output: config\.serviceworker\.output\(\),\n\s*(?!module)/,
`output: config.serviceworker.output(),\n\t\tmodule: {\n\t\t\trules: [\n\t\t\t\t{\n\t\t\t\t\ttest: /\\.ts$/,\n\t\t\t\t\tloader: 'ts-loader'\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t`
],
// Edit outputs
[
/output: config\.serviceworker\.output\(\),\n\s*(?!resolve)/,
`output: config.serviceworker.output(),\n\t\tresolve: { extensions: ['.mjs', '.js', '.ts', '.json'] },\n\t\t`
] ]
]); ]);
} }
function updateServiceWorker() { function updateServiceWorker() {
replaceInFile(path.join(projectRoot, 'src', 'service-worker.ts'), [ replaceInFile(path.join(projectRoot, "src", "service-worker.ts"), [
[`shell.concat(files);`, `(shell as string[]).concat(files as string[]);`], [`shell.concat(files);`, `(shell as string[]).concat(files as string[]);`],
[`self.skipWaiting();`, `((self as any) as ServiceWorkerGlobalScope).skipWaiting();`], [
[`self.clients.claim();`, `((self as any) as ServiceWorkerGlobalScope).clients.claim();`], `'install', event =>`,
[`fetchAndCache(request)`, `fetchAndCache(request: Request)`], `'install', <EventType extends ExtendableEvent>(event: EventType) =>`
[`self.addEventListener('activate', event =>`, `self.addEventListener('activate', (event: ExtendableEvent) =>`], ],
[`self.addEventListener('install', event =>`, `self.addEventListener('install', (event: ExtendableEvent) =>`], [
[`addEventListener('fetch', event =>`, `addEventListener('fetch', (event: FetchEvent) =>`], `self.skipWaiting();`,
`((self as any) as ServiceWorkerGlobalScope).skipWaiting();`
],
[
`'activate', event =>`,
`'activate', <EventType extends ExtendableEvent>(event: EventType) =>`
],
[
`self.clients.claim();`,
`((self as any) as ServiceWorkerGlobalScope).clients.claim();`
],
[
`'fetch', event =>`,
`'fetch', <EventType extends FetchEvent>(event: EventType) =>`
]
]); ]);
} }
@@ -240,18 +229,21 @@ function createTsConfig() {
"exclude": ["node_modules/*", "__sapper__/*", "static/*"] "exclude": ["node_modules/*", "__sapper__/*", "static/*"]
}`; }`;
createFile(path.join(projectRoot, 'tsconfig.json'), tsconfig); createFile(path.join(projectRoot, "tsconfig.json"), tsconfig);
} }
// Adds the extension recommendation // Adds the extension recommendation
function configureVsCode() { function configureVsCode() {
const dir = path.join(projectRoot, '.vscode'); const dir = path.join(projectRoot, ".vscode");
if (!fs.existsSync(dir)) { if (!fs.existsSync(dir)) {
fs.mkdirSync(dir); fs.mkdirSync(dir);
} }
createFile(path.join(projectRoot, '.vscode', 'extensions.json'), `{"recommendations": ["svelte.svelte-vscode"]}`); createFile(
path.join(projectRoot, ".vscode", "extensions.json"),
`{"recommendations": ["svelte.svelte-vscode"]}`
);
} }
function deleteThisScript() { function deleteThisScript() {
@@ -259,8 +251,8 @@ function deleteThisScript() {
// Check for Mac's DS_store file, and if it's the only one left remove it // Check for Mac's DS_store file, and if it's the only one left remove it
const remainingFiles = fs.readdirSync(path.join(__dirname)); const remainingFiles = fs.readdirSync(path.join(__dirname));
if (remainingFiles.length === 1 && remainingFiles[0] === '.DS_store') { if (remainingFiles.length === 1 && remainingFiles[0] === ".DS_store") {
fs.unlinkSync(path.join(__dirname, '.DS_store')); fs.unlinkSync(path.join(__dirname, ".DS_store"));
} }
// Check if the scripts folder is empty // Check if the scripts folder is empty
@@ -270,19 +262,15 @@ function deleteThisScript() {
} }
} }
console.log(`Adding TypeScript with ${isRollup ? "Rollup" : "webpack" }...`); console.log("Adding TypeScript with Rollup...");
addDepsToPackageJson(); addDepsToPackageJson();
changeJsExtensionToTs(path.join(projectRoot, 'src')); changeJsExtensionToTs(path.join(projectRoot, "src"));
updateSvelteFiles(); updateSvelteFiles();
if (isRollup) { updateRollupConfig();
updateRollupConfig();
} else {
updateWebpackConfig();
}
updateServiceWorker(); updateServiceWorker();
@@ -295,12 +283,8 @@ if (!argv[2]) {
deleteThisScript(); deleteThisScript();
} }
console.log('Converted to TypeScript.'); console.log("Converted to TypeScript.");
if (fs.existsSync(path.join(projectRoot, 'node_modules'))) { if (fs.existsSync(path.join(projectRoot, "node_modules"))) {
console.log(` console.log(`\nYou will need to re-run 'npm install' to get started.`);
Next:
1. run 'npm install' again to install TypeScript dependencies
2. run 'npm run build' for the @sapper imports in your project to work
`);
} }
+1
View File
@@ -17,5 +17,6 @@
background-color: #d1d5da80; background-color: #d1d5da80;
border: 1px solid transparent; border: 1px solid transparent;
border-radius: 2em; border-radius: 2em;
margin: 6px 0 0;
} }
</style> </style>
+4 -7
View File
@@ -1,4 +1,5 @@
<script> <script>
import Space from "./Space.svelte";
export let segment; export let segment;
</script> </script>
@@ -37,7 +38,7 @@
content: ''; content: '';
width: calc(100% - 1em); width: calc(100% - 1em);
height: 2px; height: 2px;
background-color: rgb(255,62,0); background-color: #3182ce;
display: block; display: block;
bottom: -1px; bottom: -1px;
} }
@@ -47,19 +48,15 @@
padding: 1em 0.5em; padding: 1em 0.5em;
display: block; display: block;
} }
.actions {
flex-grow: 1;
}
</style> </style>
<nav> <nav>
<ul> <ul>
<li><a aria-current="{segment === undefined ? 'page' : undefined}" href=".">UniDiscuss</a></li> <li><a aria-current="{segment === undefined ? 'page' : undefined}" href=".">UniDiscuss</a></li>
</ul> </ul>
<div class="actions"></div> <Space/>
<ul> <ul>
<li><a aria-current="{segment === 'ask' ? 'page' : undefined}" href="ask">Ask</a></li> <!-- <li><a aria-current="{segment === 'ask' ? 'page' : undefined}" href="ask">Ask</a></li> -->
<li><a aria-current="{segment === 'profile' ? 'page' : undefined}" href="profile">Profile</a></li> <li><a aria-current="{segment === 'profile' ? 'page' : undefined}" href="profile">Profile</a></li>
</ul> </ul>
</nav> </nav>
+15
View File
@@ -0,0 +1,15 @@
<script>
import AddComment20 from "carbon-icons-svelte/lib/AddComment20";
</script>
<style>
.root {
height: fit-content;
}
</style>
<button class="root bg-blue-600 hover:bg-blue-900 text-white font-bold py-2 px-4 rounded inline-flex items-center float-right">
<AddComment20 class="fill-current w-4 h-4 mr-2" />
<a href="/ask">Спросить</a>
</button>
+69
View File
@@ -0,0 +1,69 @@
<script>
// your script goes here
const contributors = [
{
name: 'Koskting'
},
{
name: 'Koskting'
},
{
name: 'Koskting'
},
{
name: 'Koskting'
},
{
name: 'Koskting'
},
];
</script>
<style>
.sidebar-root {
padding: 16px;
border: 1px solid #e1e4e8;
border-radius: 6px;
width: 200px;
height: fit-content;
}
h4 {
font-size: 14px;
font-weight: 600;
border-bottom: 1px solid #e1e4e8;
padding-bottom: 10px;
}
.avatar {
border-radius: 50%;
display: inline-block;
overflow: hidden;
line-height: 1;
vertical-align: middle;
border-radius: 6px;
margin-right: 10px;
}
.contributer-link {
display: flex;
padding: 8px 0;
}
</style>
<!-- markup (zero or more items) goes here -->
<div class="sidebar-root">
<h4>Most helpful</h4>
{#each contributors as contributor}
<a class="contributer-link" href="/{contributor.name}">
<img
class="avatar"
src="https://avatars0.githubusercontent.com/u/2854919?s=40&amp;v=4"
width="20"
height="20"
alt="@jamesmosier"
>
<span>{contributor.name}</span>
</a>
{/each}
</div>
+9
View File
@@ -0,0 +1,9 @@
<style>
.actions {
flex-grow: 1;
}
</style>
<div class="actions"></div>
+5
View File
@@ -0,0 +1,5 @@
<style global>
@tailwind base;
@tailwind components;
@tailwind utilities;
</style>
+23
View File
@@ -0,0 +1,23 @@
<script>
import ArrowUp16 from "carbon-icons-svelte/lib/ArrowUp16";
import Chip from "./Chip.svelte";
export let value = 0;
</script>
<div class="vote">
<ArrowUp16 />
<Chip value="{value}" />
</div>
<style>
.vote {
display: flex;
flex-direction: column;
align-items: center;
width: 56px;
justify-content: center;
margin-right: 10px;
}
</style>
+16 -3
View File
@@ -1,22 +1,35 @@
<script> <script>
import Tailwindcss from '../components/Tailwindcss.svelte';
import Nav from '../components/Nav.svelte'; import Nav from '../components/Nav.svelte';
import SideBar from "../components/SideBar.svelte";
export let segment; export let segment;
</script> </script>
<style> <style>
main { main {
position: relative; display: flex;
max-width: 56em;
background-color: white; background-color: white;
padding: 2em; padding: 15px 2em;
margin: 0 auto; margin: 0 auto;
box-sizing: border-box; box-sizing: border-box;
} }
@media only screen and (max-width : 768px) {
main {
flex-direction: column;
align-items: center;
padding: 10px;
}
}
</style> </style>
<Tailwindcss />
<Nav {segment}/> <Nav {segment}/>
<main> <main>
<slot></slot> <slot></slot>
<SideBar />
</main> </main>
-28
View File
@@ -1,28 +0,0 @@
import posts from './_posts.js';
const lookup = new Map();
posts.forEach(post => {
lookup.set(post.slug, JSON.stringify(post));
});
export function get(req, res, next) {
// the `slug` parameter is available because
// this file is called [slug].json.js
const { slug } = req.params;
if (lookup.has(slug)) {
res.writeHead(200, {
'Content-Type': 'application/json'
});
res.end(lookup.get(slug));
} else {
res.writeHead(404, {
'Content-Type': 'application/json'
});
res.end(JSON.stringify({
message: `Not found`
}));
}
}
-64
View File
@@ -1,64 +0,0 @@
<script context="module">
export async function preload({ params }) {
// the `slug` parameter is available because
// this file is called [slug].svelte
const res = await this.fetch(`blog/${params.slug}.json`);
const data = await res.json();
if (res.status === 200) {
return { post: data };
} else {
this.error(res.status, data.message);
}
}
</script>
<script>
export let post;
</script>
<style>
/*
By default, CSS is locally scoped to the component,
and any unused styles are dead-code-eliminated.
In this page, Svelte can't know which elements are
going to appear inside the {{{post.html}}} block,
so we have to use the :global(...) modifier to target
all elements inside .content
*/
.content :global(h2) {
font-size: 1.4em;
font-weight: 500;
}
.content :global(pre) {
background-color: #f9f9f9;
box-shadow: inset 1px 1px 5px rgba(0, 0, 0, 0.05);
padding: 0.5em;
border-radius: 2px;
overflow-x: auto;
}
.content :global(pre) :global(code) {
background-color: transparent;
padding: 0;
}
.content :global(ul) {
line-height: 1.5;
}
.content :global(li) {
margin: 0 0 0.5em 0;
}
</style>
<svelte:head>
<title>{post.title}</title>
</svelte:head>
<h1>{post.title}</h1>
<div class="content">
{@html post.html}
</div>
-92
View File
@@ -1,92 +0,0 @@
// Ordinarily, you'd generate this data from markdown files in your
// repo, or fetch them from a database of some kind. But in order to
// avoid unnecessary dependencies in the starter template, and in the
// service of obviousness, we're just going to leave it here.
// This file is called `_posts.js` rather than `posts.js`, because
// we don't want to create an `/blog/posts` route — the leading
// underscore tells Sapper not to do that.
const posts = [
{
title: 'What is Sapper?',
slug: 'what-is-sapper',
html: `
<p>First, you have to know what <a href='https://svelte.dev'>Svelte</a> is. Svelte is a UI framework with a bold new idea: rather than providing a library that you write code with (like React or Vue, for example), it's a compiler that turns your components into highly optimized vanilla JavaScript. If you haven't already read the <a href='https://svelte.dev/blog/frameworks-without-the-framework'>introductory blog post</a>, you should!</p>
<p>Sapper is a Next.js-style framework (<a href='blog/how-is-sapper-different-from-next'>more on that here</a>) built around Svelte. It makes it embarrassingly easy to create extremely high performance web apps. Out of the box, you get:</p>
<ul>
<li>Code-splitting, dynamic imports and hot module replacement, powered by webpack</li>
<li>Server-side rendering (SSR) with client-side hydration</li>
<li>Service worker for offline support, and all the PWA bells and whistles</li>
<li>The nicest development experience you've ever had, or your money back</li>
</ul>
<p>It's implemented as Express middleware. Everything is set up and waiting for you to get started, but you keep complete control over the server, service worker, webpack config and everything else, so it's as flexible as you need it to be.</p>
`
},
{
title: 'How to use Sapper',
slug: 'how-to-use-sapper',
html: `
<h2>Step one</h2>
<p>Create a new project, using <a href='https://github.com/Rich-Harris/degit'>degit</a>:</p>
<pre><code>npx degit "sveltejs/sapper-template#rollup" my-app
cd my-app
npm install # or yarn!
npm run dev
</code></pre>
<h2>Step two</h2>
<p>Go to <a href='http://localhost:3000'>localhost:3000</a>. Open <code>my-app</code> in your editor. Edit the files in the <code>src/routes</code> directory or add new ones.</p>
<h2>Step three</h2>
<p>...</p>
<h2>Step four</h2>
<p>Resist overdone joke formats.</p>
`
},
{
title: 'Why the name?',
slug: 'why-the-name',
html: `
<p>In war, the soldiers who build bridges, repair roads, clear minefields and conduct demolitions — all under combat conditions — are known as <em>sappers</em>.</p>
<p>For web developers, the stakes are generally lower than those for combat engineers. But we face our own hostile environment: underpowered devices, poor network connections, and the complexity inherent in front-end engineering. Sapper, which is short for <strong>S</strong>velte <strong>app</strong> mak<strong>er</strong>, is your courageous and dutiful ally.</p>
`
},
{
title: 'How is Sapper different from Next.js?',
slug: 'how-is-sapper-different-from-next',
html: `
<p><a href='https://github.com/zeit/next.js'>Next.js</a> is a React framework from <a href='https://vercel.com/'>Vercel</a>, and is the inspiration for Sapper. There are a few notable differences, however:</p>
<ul>
<li>It's powered by <a href='https://svelte.dev'>Svelte</a> instead of React, so it's faster and your apps are smaller</li>
<li>Instead of route masking, we encode route parameters in filenames. For example, the page you're looking at right now is <code>src/routes/blog/[slug].svelte</code></li>
<li>As well as pages (Svelte components, which render on server or client), you can create <em>server routes</em> in your <code>routes</code> directory. These are just <code>.js</code> files that export functions corresponding to HTTP methods, and receive Express <code>request</code> and <code>response</code> objects as arguments. This makes it very easy to, for example, add a JSON API such as the one <a href='blog/how-is-sapper-different-from-next.json'>powering this very page</a></li>
<li>Links are just <code>&lt;a&gt;</code> elements, rather than framework-specific <code>&lt;Link&gt;</code> components. That means, for example, that <a href='blog/how-can-i-get-involved'>this link right here</a>, despite being inside a blob of HTML, works with the router as you'd expect.</li>
</ul>
`
},
{
title: 'How can I get involved?',
slug: 'how-can-i-get-involved',
html: `
<p>We're so glad you asked! Come on over to the <a href='https://github.com/sveltejs/svelte'>Svelte</a> and <a href='https://github.com/sveltejs/sapper'>Sapper</a> repos, and join us in the <a href='https://svelte.dev/chat'>Discord chatroom</a>. Everyone is welcome, especially you!</p>
`
}
];
posts.forEach(post => {
post.html = post.html.replace(/^\t{3}/gm, '');
});
export default posts;
-16
View File
@@ -1,16 +0,0 @@
import posts from './_posts.js';
const contents = JSON.stringify(posts.map(post => {
return {
title: post.title,
slug: post.slug
};
}));
export function get(req, res) {
res.writeHead(200, {
'Content-Type': 'application/json'
});
res.end(contents);
}
-34
View File
@@ -1,34 +0,0 @@
<script context="module">
export function preload() {
return this.fetch(`blog.json`).then(r => r.json()).then(posts => {
return { posts };
});
}
</script>
<script>
export let posts;
</script>
<style>
ul {
margin: 0 0 1em 0;
line-height: 1.5;
}
</style>
<svelte:head>
<title>Blog</title>
</svelte:head>
<h1>Recent posts</h1>
<ul>
{#each posts as post}
<!-- we're using the non-standard `rel=prefetch` attribute to
tell Sapper to load the data for the page as soon as
the user hovers over the link or taps it, instead of
waiting for the 'click' event -->
<li><a rel="prefetch" href="blog/{post.slug}">{post.title}</a></li>
{/each}
</ul>
+30
View File
@@ -0,0 +1,30 @@
import _discussions from './_discussions.js';
const lookup = new Map();
_discussions.forEach(discussion => {
lookup.set(`${discussion.id}`, JSON.stringify(discussion));
});
export function get(req, res, next) {
// the `id` parameter is available because
// this file is called [id].json.js
const { id } = req.params;
if (lookup.has(id)) {
res.writeHead(200, {
"Content-Type": "application/json"
});
res.end(lookup.get(id));
} else {
res.writeHead(404, {
"Content-Type": "application/json"
});
res.end(
JSON.stringify({
message: `Not found`
})
);
}
}
+66
View File
@@ -0,0 +1,66 @@
<script context="module">
export async function preload({ params }) {
// the `id` parameter is available because
// this file is called [id].svelte
const res = await this.fetch(`discussion/${params.id}.json`);
const data = await res.json();
if (res.status === 200) {
return { discussion: data };
} else {
this.error(res.status, data.message);
}
}
</script>
<script>
export let discussion;
</script>
<style>
</style>
<svelte:head>
<title>{discussion.title}</title>
</svelte:head>
<h1>{discussion.title}</h1>
<div class="my-1 px-1 w-full md:w-1/2 lg:my-4 lg:px-4 lg:w-1/3">
<!-- Article -->
<article class="overflow-hidden rounded-lg shadow-lg">
<a href="#">
<img alt="Placeholder" class="block h-auto w-full" src="https://picsum.photos/600/400/?random">
</a>
<header class="flex items-center justify-between leading-tight p-2 md:p-4">
<h1 class="text-lg">
<a class="no-underline hover:underline text-black" href="#">
Article Title
</a>
</h1>
<p class="text-grey-darker text-sm">
14/4/19
</p>
</header>
<footer class="flex items-center justify-between leading-none p-2 md:p-4">
<a class="flex items-center no-underline hover:underline text-black" href="#">
<img alt="Placeholder" class="block rounded-full" src="https://picsum.photos/32/32/?random">
<p class="ml-2 text-sm">
Author Name
</p>
</a>
<a class="no-underline text-grey-darker hover:text-red-dark" href="#">
<span class="hidden">Like</span>
<i class="fa fa-heart"></i>
</a>
</footer>
</article>
<!-- END Article -->
</div>
<!-- END Column -->
+150
View File
@@ -0,0 +1,150 @@
// Ordinarily, you'd generate this data from markdown files in your
// repo, or fetch them from a database of some kind. But in order to
// avoid unnecessary dependencies in the starter template, and in the
// service of obviousness, we're just going to leave it here.
// This file is called `_discussions.js` rather than `posts.js`, because
// we don't want to create an `/blog/posts` route — the leading
// underscore tells Sapper not to do that.
export default [
{
title: "What is Sapper?",
id: 1,
author: {
name: "babdraa",
avatar: "https://avatars3.githubusercontent.com/u/24832873?s=60&v=4"
},
question: "Hello, I was thinking… Is there a way to get static props for non-page components without passing props from page component? Eg. navigation which is shared across many pages.",
createdAt: Date.now(),
comments: [
{
name: "babdraa",
avatar: "https://avatars3.githubusercontent.com/u/24832873?s=60&v=4",
comment:
"getStaticProps must always be called from a page located in pages/*"
},
{
name: "crana",
avatar: "https://avatars1.githubusercontent.com/u/31749594?s=60&v=4",
comment:
"Hello, thank you for reply. Of course I know that :-) I was just thinking if there is some way to do same as getStaticProps for other components too. I don't think such feature is completely necessary, though."
},
{
name: "loris",
avatar: "https://avatars3.githubusercontent.com/u/11896398?s=60&v=4",
comment:
"getStaticProps must always be called from a page located in pages/*"
}
]
},
{
title: "How to use Sapper",
id: 2,
author: {
name: "babdraa",
avatar: "https://avatars3.githubusercontent.com/u/24832873?s=60&v=4"
},
question:
"Hello, I was thinking… Is there a way to get static props for non-page components without passing props from page component? Eg. navigation which is shared across many pages.",
createdAt: Date.now(),
comments: [
{
name: "rawe",
avatar: "https://avatars1.githubusercontent.com/u/31749594?s=60&v=4",
comment:
"Hello, thank you for reply. Of course I know that :-) I was just thinking if there is some way to do same as getStaticProps for other components too. I don't think such feature is completely necessary, though."
},
{
name: "hlaow",
avatar: "https://avatars3.githubusercontent.com/u/11896398?s=60&v=4",
comment:
"getStaticProps must always be called from a page located in pages/*"
}
]
},
{
title: "Why the name?",
id: 3,
author: {
name: "babdraa",
avatar: "https://avatars3.githubusercontent.com/u/24832873?s=60&v=4"
},
question:
"Hello, I was thinking… Is there a way to get static props for non-page components without passing props from page component? Eg. navigation which is shared across many pages.",
createdAt: Date.now(),
comments: [
{
name: "babdraa",
avatar: "https://avatars3.githubusercontent.com/u/24832873?s=60&v=4",
comment:
"getStaticProps must always be called from a page located in pages/*"
},
{
name: "crana",
avatar: "https://avatars1.githubusercontent.com/u/31749594?s=60&v=4",
comment:
"Hello, thank you for reply. Of course I know that :-) I was just thinking if there is some way to do same as getStaticProps for other components too. I don't think such feature is completely necessary, though."
},
{
name: "loris",
avatar: "https://avatars3.githubusercontent.com/u/11896398?s=60&v=4",
comment:
"getStaticProps must always be called from a page located in pages/*"
}
]
},
{
title: "How is Sapper different from Next.js?",
id: 4,
author: {
name: "babdraa",
avatar: "https://avatars3.githubusercontent.com/u/24832873?s=60&v=4"
},
question: "Hello, I was thinking… Is there a way to get static props for non-page components without passing props from page component? Eg. navigation which is shared across many pages.",
createdAt: Date.now(),
comments: [
{
name: "babdraa",
avatar: "https://avatars3.githubusercontent.com/u/24832873?s=60&v=4",
comment:
"getStaticProps must always be called from a page located in pages/*"
},
{
name: "crana",
avatar: "https://avatars1.githubusercontent.com/u/31749594?s=60&v=4",
comment:
"Hello, thank you for reply. Of course I know that :-) I was just thinking if there is some way to do same as getStaticProps for other components too. I don't think such feature is completely necessary, though."
},
{
name: "loris",
avatar: "https://avatars3.githubusercontent.com/u/11896398?s=60&v=4",
comment:
"getStaticProps must always be called from a page located in pages/*"
}
]
},
{
title: "How can I get involved?",
id: 5,
author: {
name: "living",
avatar: "https://avatars3.githubusercontent.com/u/24832873?s=60&v=4"
},
question: "Hello, I was thinking… Is there a way to get static props for non-page components without passing props from page component? Eg. navigation which is shared across many pages.",
createdAt: Date.now(),
comments: [
{
name: "gbenga",
avatar: "https://avatars3.githubusercontent.com/u/11896398?s=60&v=4",
comment:
"getStaticProps must always be called from a page located in pages/*"
}
]
}
];
+92 -23
View File
@@ -1,6 +1,9 @@
<script> <script>
import ArrowUp16 from "carbon-icons-svelte/lib/ArrowUp16"; import AddComment20 from "carbon-icons-svelte/lib/AddComment20";
import Chip from "../components/Chip.svelte"; import Vote from "../components/Vote.svelte";
import Space from "../components/Space.svelte";
import NewQuestion from "../components/NewQuestion.svelte";
const discussions = [ const discussions = [
{ {
id: 1, id: 1,
@@ -12,7 +15,8 @@
'ибэит', 'икс' 'ибэит', 'икс'
], ],
answered: false, answered: false,
comments: 10 comments: 10,
votes: 10,
}, },
{ {
id: 2, id: 2,
@@ -24,7 +28,8 @@
'иибрт', 'иее' 'иибрт', 'иее'
], ],
answered: false, answered: false,
comments: 2 comments: 2,
votes: 2,
}, },
{ {
id: 3, id: 3,
@@ -36,7 +41,8 @@
'ибэит', 'иее', 'иибрт', 'ИПИГ' 'ибэит', 'иее', 'иибрт', 'ИПИГ'
], ],
answered: false, answered: false,
comments: 10 comments: 10,
votes: 10,
}, },
{ {
id: 4, id: 4,
@@ -48,24 +54,82 @@
'ИЭКСУ', 'ИМБТ', 'ИМИ', 'ИПТДМ', 'ИИИР', 'ГФ', 'ХТФ', 'ИДЗО', 'УИИ', 'УНИ' 'ИЭКСУ', 'ИМБТ', 'ИМИ', 'ИПТДМ', 'ИИИР', 'ГФ', 'ХТФ', 'ИДЗО', 'УИИ', 'УНИ'
], ],
answered: false, answered: false,
comments: 10 comments: 15,
votes: 15,
},
{
id: 1,
title: 'How do I pass Anicimov?',
author: {
name: 'rotimibest',
},
tags: [
'ибэит', 'икс'
],
answered: false,
comments: 7,
votes: 7,
},
{
id: 2,
title: 'Where do I find the nearest restaurant?',
author: {
name: 'attronaldo',
},
tags: [
'иибрт', 'иее'
],
answered: false,
comments: 4,
votes: 4,
},
{
id: 3,
title: 'Who is Nikolenko?',
author: {
name: 'donald',
},
tags: [
'ибэит', 'иее', 'иибрт', 'ИПИГ'
],
answered: false,
comments: 100,
votes: 100,
},
{
id: 4,
title: 'Archive discussion button',
author: {
name: 'acharlesvv',
},
tags: [
'ИЭКСУ', 'ИМБТ', 'ИМИ', 'ИПТДМ', 'ИИИР', 'ГФ', 'ХТФ', 'ИДЗО', 'УИИ', 'УНИ'
],
answered: false,
comments: 5,
votes: 5,
} }
] ];
</script> </script>
<svelte:head> <svelte:head>
<title>Unidiscuss - Help students in your university</title> <title>Unidiscuss - Help students in your university</title>
</svelte:head> </svelte:head>
<div class="root"> <div class="root">
<div class="flex justify-end mb-5">
<NewQuestion />
</div>
{#each discussions as discussion} {#each discussions as discussion}
<div class="discussion-box"> <div class="discussion-box">
<div class="discussion-vote"> <Vote value="{discussion.votes}" />
<ArrowUp16 />
<Chip value="{discussion.comments}" />
</div>
<div class="discussion-topic-author"> <div class="discussion-topic-author">
<h4><a rel="prefetch" href="blog/{discussion.id}">{discussion.title}</a></h4> <h4><a rel="prefetch" href="discussion/{discussion.id}">{discussion.title}</a></h4>
<span>{discussion.author.name} asked 1 day ago</span> <span>{discussion.author.name} asked 1 day ago</span>
</div>
<Space />
<div class="discussion-comments">
<AddComment20 />
<span>{discussion.comments}</span>
</div> </div>
</div> </div>
{/each} {/each}
@@ -73,13 +137,14 @@
<style> <style>
.root { .root {
margin: 0 auto; margin: 0 auto 20px;
width: 600px;
} }
.discussion-box { .discussion-box {
border-bottom: 1px solid #eaecef; border-top: 1px solid #eaecef;
display: flex; display: flex;
align-items: center; align-items: flex-start;
padding: 16px; padding: 16px;
} }
@@ -91,17 +156,21 @@
margin: 0; margin: 0;
} }
.discussion-vote { .discussion-topic-author {
display: flex; margin-right: 20px;
flex-direction: column;
align-items: center;
width: 56px;
justify-content: center;
margin-right: 10px;
} }
.discussion-topic-author span{ .discussion-topic-author span{
color: #586069; color: #586069;
font-size: 12px;; font-size: 12px;;
} }
.discussion-comments {
display: flex;
}
@media only screen and (max-width : 768px) {
.root {
width: 100%;
}
}
</style> </style>
+16
View File
@@ -0,0 +1,16 @@
module.exports = {
purge: {
mode: 'all',
content: ['./**/**/*.html', './**/**/*.svelte'],
options: {
whitelistPatterns: [/svelte-/],
},
},
theme: {
extend: {},
},
variants: {},
plugins: [],
};