Skip to content

Commit

Permalink
virtual keyboard on bottom (#1)
Browse files Browse the repository at this point in the history
Co-authored-by: rocka <[email protected]>
  • Loading branch information
eagleoflqj and rocka authored Nov 3, 2024
1 parent 73f19bb commit 6eec288
Show file tree
Hide file tree
Showing 26 changed files with 945 additions and 0 deletions.
31 changes: 31 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
name: ci

on:
push:
branches:
- master
pull_request:

jobs:
build:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v4

- uses: actions/setup-node@v4
with:
node-version: 22.x

- name: Install node dependencies
run: |
npm i -g pnpm
pnpm i
- name: Lint and Check type
run: |
pnpm run lint
pnpm run check
- name: Build
run: pnpm run build
26 changes: 26 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*

node_modules
dist
dist-ssr
*.local

# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?

pnpm-lock.yaml
3 changes: 3 additions & 0 deletions .vscode/extensions.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"recommendations": ["Vue.volar"]
}
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Slide Lab
Web App for slide input experiment.

## Credits
* [theme-designer](https://github.com/fcitx5-android/theme-designer)
4 changes: 4 additions & 0 deletions eslint.config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import antfu from '@antfu/eslint-config'

export default antfu({
})
13 changes: 13 additions & 0 deletions index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Slide Lab</title>
</head>
<body>
<div id="app"></div>
<script type="module" src="./src/main.ts"></script>
</body>
</html>
25 changes: 25 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
{
"name": "slide-lab",
"private": true,
"version": "0.1.0",
"type": "module",
"scripts": {
"dev": "vite --host",
"lint": "eslint src",
"lint:fix": "eslint --fix src",
"check": "vue-tsc --noEmit",
"build": "vue-tsc -b && vite build",
"preview": "vite preview --host"
},
"license": "AGPL-3.0-or-later",
"devDependencies": {
"@antfu/eslint-config": "^3.8.0",
"@vitejs/plugin-vue": "^5.1.4",
"eslint": "^9.14.0",
"material-design-icons-iconfont": "^6.7.0",
"typescript": "~5.6.2",
"vite": "^5.4.10",
"vue": "^3.5.12",
"vue-tsc": "^2.1.8"
}
}
43 changes: 43 additions & 0 deletions src/App.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<script setup lang="ts">
import type { ThemePreference } from './types/ThemePreference'
import type { ThemeProperties } from './types/ThemeProperties'
import { ref } from 'vue'
import KeyboardWindow from './components/KeyboardWindow.vue'
import { TextKeyboard } from './layouts'
import { PixelDark } from './theme-preset'
import { PunctuationPosition } from './types/ThemePreference'
const preference = ref<ThemePreference>({
border: false,
horizontalMargin: 3,
verticalMargin: 7,
radius: 4,
puncPosition: PunctuationPosition.Bottom,
})
const theme = ref<ThemeProperties>(PixelDark)
</script>

<template>
<div class="input-view">
<KeyboardWindow :preference="preference" :layout="TextKeyboard" :theme="theme" />
</div>
</template>

<style>
body {
margin: 0; /* Content fills 100% width on phone. */
}
.input-view {
height: 230px;
width: 100%;
display: flex;
flex-direction: column;
position: fixed;
bottom: 0;
}
</style>
135 changes: 135 additions & 0 deletions src/components/KeyView/KeyView.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
<script setup lang="ts">
import type { Component, StyleValue } from 'vue'
import type { KeyAppearance } from '../../types/KeyDef'
import type { ThemePreference } from '../../types/ThemePreference'
import type { ThemeProperties } from '../../types/ThemeProperties'
import { computed, ref } from 'vue'
import { KeyAppearanceType, KeyAppearanceVariant, KeyViewId } from '../../types/KeyDef'
import KeyViewAltText from './KeyViewAltText.vue'
import KeyViewImage from './KeyViewImage.vue'
import KeyViewText from './KeyViewText.vue'
interface KeyViewProps {
preference: ThemePreference
appearance: KeyAppearance
theme: ThemeProperties
}
const props = defineProps<KeyViewProps>()
const keyStyles = computed<StyleValue>(() => ({
flexBasis: `${props.appearance.percentWidth}%`,
}))
const pressed = ref(false)
const ComponentType = {
[KeyAppearanceType.Text]: KeyViewText,
[KeyAppearanceType.AltText]: KeyViewAltText,
[KeyAppearanceType.Image]: KeyViewImage,
}
const appearanceType = computed<Component<KeyViewProps>>(() => ComponentType[props.appearance.type])
const bkgStyle = computed<StyleValue>(() => {
const { preference, appearance, theme } = props
if (!preference.border) {
if (appearance.forceBordered) {
switch (appearance.viewId) {
case KeyViewId.Space: return {
backgroundColor: theme.spaceBarColor,
top: '16px',
right: '10px',
bottom: '16px',
left: '10px',
borderRadius: `${preference.radius}px`,
}
case KeyViewId.Return: return {
backgroundColor: theme.accentKeyBackgroundColor,
width: '35px',
height: '35px',
borderRadius: '50%',
}
}
}
return {
display: 'none',
}
}
const bkgColor = computed(() => {
switch (appearance.variant) {
case KeyAppearanceVariant.Normal:
case KeyAppearanceVariant.AltForeground:
return theme.keyBackgroundColor
case KeyAppearanceVariant.Alternative:
return theme.altKeyBackgroundColor
case KeyAppearanceVariant.Accent:
return theme.accentKeyBackgroundColor
default:
return theme.keyBackgroundColor
}
})
return {
backgroundColor: bkgColor.value,
top: `${preference.verticalMargin}px`,
right: `${preference.horizontalMargin}px`,
bottom: `${preference.verticalMargin}px`,
left: `${preference.horizontalMargin}px`,
borderRadius: preference.border ? `${preference.radius}px` : '0',
boxShadow: preference.border ? `0 1px 0 ${theme.keyShadowColor}` : 'none',
}
})
const highlightStyle = computed<StyleValue>(() => {
const { preference, theme } = props
return {
backgroundColor: theme.keyPressHighlightColor,
top: `${preference.verticalMargin}px`,
right: `${preference.horizontalMargin}px`,
bottom: `${preference.verticalMargin}px`,
left: `${preference.horizontalMargin}px`,
borderRadius: preference.border ? `${preference.radius}px` : '0',
}
})
</script>

<template>
<div class="keyview" :style="keyStyles" @mousedown="pressed = true" @mouseup="pressed = false">
<div class="keyview__bg" :style="bkgStyle" />
<component :is="appearanceType" :preference="preference" :appearance="appearance" :theme="theme" />
<div class="keyview__highlight" :style="highlightStyle" />
</div>
</template>

<style>
.keyview {
position: relative;
box-sizing: border-box;
display: flex;
flex-grow: 0;
/* TODO: support Top-Right punctuation layout */
flex-direction: column;
align-items: center;
justify-content: center;
overflow: hidden;
}
.keyview__bg {
position: absolute;
}
.keyview__highlight {
visibility: hidden;
position: absolute;
}
.keyview:active .keyview__highlight {
visibility: visible;
}
.keyview__fg {
z-index: 1;
}
</style>
60 changes: 60 additions & 0 deletions src/components/KeyView/KeyViewAltText.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
<script setup lang="ts">
import type { StyleValue } from 'vue'
import type { KeyAppearanceAltText } from '../../types/KeyDef'
import type { ThemePreference } from '../../types/ThemePreference'
import type { ThemeProperties } from '../../types/ThemeProperties'
import { computed } from 'vue'
import { KeyAppearanceVariant, KeyTextTypeface } from '../../types/KeyDef'
const props = defineProps<{
preference: ThemePreference
appearance: KeyAppearanceAltText
theme: ThemeProperties
}>()
const fgColor = computed(() => {
switch (props.appearance.variant) {
case KeyAppearanceVariant.Normal:
return props.theme.keyTextColor
case KeyAppearanceVariant.AltForeground:
case KeyAppearanceVariant.Alternative:
return props.theme.altKeyTextColor
case KeyAppearanceVariant.Accent:
return props.theme.accentKeyTextColor
default:
return props.theme.keyTextColor
}
})
const mainTextStyle = computed<StyleValue>(() => ({
color: fgColor.value,
fontSize: `${props.appearance.textSize}px`,
fontWeight: props.appearance.typeface === KeyTextTypeface.Bold ? 'bold' : 'normal',
}))
const altFgColor = computed(() => {
switch (props.appearance.variant) {
case KeyAppearanceVariant.Normal:
case KeyAppearanceVariant.AltForeground:
case KeyAppearanceVariant.Alternative:
return props.theme.altKeyTextColor
case KeyAppearanceVariant.Accent:
return props.theme.accentKeyTextColor
default:
return props.theme.altKeyTextColor
}
})
const altTextStyle = computed<StyleValue>(() => ({
color: altFgColor.value,
fontSize: '10.7px',
fontWeight: 'bold',
transform: 'translateY(-2px)',
}))
</script>

<template>
<div class="keyview__fg" :style="mainTextStyle" v-text="appearance.displayText" />
<div class="keyview__fg" :style="altTextStyle" v-text="appearance.altText" />
</template>
40 changes: 40 additions & 0 deletions src/components/KeyView/KeyViewImage.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<script setup lang="ts">
import type { StyleValue } from 'vue'
import type { KeyAppearanceImage } from '../../types/KeyDef'
import type { ThemePreference } from '../../types/ThemePreference'
import type { ThemeProperties } from '../../types/ThemeProperties'
import { computed } from 'vue'
import { KeyAppearanceVariant, KeyImageResourceIcon } from '../../types/KeyDef'
const props = defineProps<{
preference: ThemePreference
appearance: KeyAppearanceImage
theme: ThemeProperties
}>()
const icon = computed(() => KeyImageResourceIcon[props.appearance.src] ?? 'question_mark')
const fgColor = computed(() => {
switch (props.appearance.variant) {
case KeyAppearanceVariant.Normal:
case KeyAppearanceVariant.AltForeground:
case KeyAppearanceVariant.Alternative:
return props.theme.altKeyTextColor
case KeyAppearanceVariant.Accent:
return props.theme.accentKeyTextColor
default:
return props.theme.altKeyTextColor
}
})
const fgStyle = computed<StyleValue>(() => ({
color: fgColor.value,
fontFamily: 'Material Icons',
fontSize: '24px',
}))
</script>

<template>
<div class="keyview__fg" :style="fgStyle" v-text="icon" />
</template>
Loading

0 comments on commit 6eec288

Please sign in to comment.