diff --git a/index.html b/index.html
index bd539cb..618cce0 100644
--- a/index.html
+++ b/index.html
@@ -8,11 +8,7 @@
-
+
{{#if process.env.NODE_ENV === 'development' }}
diff --git a/public/appfont.ttf b/public/appfont.ttf
new file mode 100644
index 0000000..0bd7eb0
Binary files /dev/null and b/public/appfont.ttf differ
diff --git a/public/favicon.ico b/public/favicon.ico
index ca9a21a..c73851a 100644
Binary files a/public/favicon.ico and b/public/favicon.ico differ
diff --git a/src/components/banner.vue b/src/components/banner.vue
index 4acd392..71c47c2 100644
--- a/src/components/banner.vue
+++ b/src/components/banner.vue
@@ -43,7 +43,7 @@
.info {
display: flex;
flex-direction: column;
- width: 212px;
+ width: 256px;
padding: 8px 12px;
background: var(--color-plain-1);
diff --git a/src/lib/checks.js b/src/lib/checks.js
index 4ff824c..5cc2c0a 100644
--- a/src/lib/checks.js
+++ b/src/lib/checks.js
@@ -4,8 +4,15 @@
* @date 2023/07/18 19:11:01
*/
+import { IS_SAFARI } from './env.js'
+
// 用canvas检测图形/图象的支持
export function checkCanvas(type) {
+ // macos下的safari, 调用webgpu,会崩溃
+ // 所以, webgpu不能用canvas调用来判断
+ if (type == 'webgpu') {
+ return !!navigator.gpu ^ 0
+ }
try {
var canvas = document.createElement('canvas')
var ctx = canvas.getContext(type)
@@ -16,10 +23,9 @@ export function checkCanvas(type) {
}
}
-export function checkMedia(type, isAudio = true) {
+export function checkMedia(type, isAudio = 1) {
let ctx = isAudio ? new Audio() : document.createElement('video')
let res = ctx.canPlayType(type)
- console.log(isAudio, res)
if (res === 'maybe' || res === 'probably') {
return 1
}
diff --git a/src/lib/env.js b/src/lib/env.js
index 6ebc69e..5422c2c 100644
--- a/src/lib/env.js
+++ b/src/lib/env.js
@@ -4,18 +4,23 @@
* @date 2023/07/18 16:16:02
*/
-const UA = navigator.userAgent.toLowerCase()
-const UNKNOW_MATCH = [null, 'unknow']
+const UNKNOW = 'Unknow'
-const IS_CHROME = !!window.chrome
-const IS_FIREFOX = !!window.sidebar
+export const UA = navigator.userAgent.toLowerCase()
+export const UNKNOW_MATCH = [null, UNKNOW]
-const IS_LINUX = UA.includes('linux')
-const IS_WIN = UA.includes('windows nt')
-const IS_ANDROID = UA.includes('android')
-const IS_IOS =
+/* 分辨率 */
+const SCREEN = `${screen.width} x ${screen.height}`
+
+/* 操作系统 */
+export const IS_LINUX = UA.includes('linux')
+export const IS_WIN = UA.includes('windows nt')
+export const IS_MACOS = UA.includes('mac os x')
+
+export const IS_ANDROID = UA.includes('android')
+export const IS_IOS =
UA.includes('iphone') || UA.includes('ipad') || UA.includes('ipod')
-const IS_MOBILE = IS_ANDROID || IS_IOS || UA.includes('mobile')
+export const IS_MOBILE = IS_ANDROID || IS_IOS || UA.includes('mobile')
const OS_NAME = IS_ANDROID
? 'Android'
@@ -25,12 +30,18 @@ const OS_NAME = IS_ANDROID
? 'Linux'
: IS_WIN
? 'Windows'
- : 'MacOS'
+ : IS_MACOS
+ ? 'MacOS'
+ : UNKNOW
const OS_VERSION = IS_ANDROID ? UA.match(/android ([\d\.]*?);/)[1] : ''
-const SCREEN = `${screen.width} x ${screen.height}`
+/* 浏览器 */
+export const IS_CHROME = !!window.chrome
+export const IS_FIREFOX = 'MozAppearance' in document.documentElement.style
+export const IS_SAFARI = (IS_MACOS || IS_IOS) && !!window.safari
-const BROWSER_NAME = IS_IOS
+/* 浏览器名称 */
+const BROWSER_NAME = IS_SAFARI
? 'Safari'
: IS_CHROME
? 'Chrome'
@@ -38,16 +49,25 @@ const BROWSER_NAME = IS_IOS
? 'Firefox'
: 'Unknow'
+/* 浏览器版本 */
const GENERAL_VERSION = UA.match(/version\/([\d\.]*?) /) || UNKNOW_MATCH
-const CHROME_VERSION =
- IS_CHROME && (UA.match(/chrome\/([\d\.]*?) /) || UNKNOW_MATCH)
-const IPAD_WEBKIT_VERSION =
- IS_IOS && (UA.match(/crios\/([\d\.]*?) /) || GENERAL_VERSION)
+const CHROME_VERSION = UA.match(/chrome\/([\d\.]*?) /) || UNKNOW_MATCH
+const IPAD_WEBKIT_VERSION = UA.match(/crios\/([\d\.]*?) /) || GENERAL_VERSION
+const FIREFOX_VERSION = UA.match(/firefox\/([\d\.]*)/) || UNKNOW_MATCH
const BROWSER_VERSION = IS_IOS
? IPAD_WEBKIT_VERSION[1]
: IS_CHROME
? CHROME_VERSION[1]
+ : IS_FIREFOX
+ ? FIREFOX_VERSION[1]
: GENERAL_VERSION[1]
+// 是否支持 Import assertions
+export const SUPPORT_ASSERTIONS = IS_CHROME
+ ? CHROME_VERSION[1].split('.').shift() > 91
+ : IS_SAFARI
+ ? GENERAL_VERSION[1].split('.').shift() >= 15
+ : false
+
export { OS_NAME, OS_VERSION, BROWSER_NAME, BROWSER_VERSION, SCREEN }
diff --git a/src/store.js b/src/store.js
index 9a0e402..dd976a2 100644
--- a/src/store.js
+++ b/src/store.js
@@ -12,7 +12,7 @@ const store = reactive({
{
name: '音频支持',
total: 0,
- factor: 80,
+ factor: 70,
scores: [
!!window.AudioContext ^ 0,
checkMedia('audio/wav'),
@@ -29,19 +29,17 @@ const store = reactive({
'flac support',
'aac support',
'ogg support',
- 'webm support',
- 'Dolby Digital support',
- 'Dolby Digital Plus support'
+ 'webm support'
]
},
{
name: '视频支持',
total: 0,
- factor: 80,
+ factor: 70,
scores: [
checkMedia('video/mp4; codecs="mp4v.20.8"', 0),
checkMedia('video/mp4', 0),
- checkMedia('video/mp4; codecs="hev1"', 0),
+ checkMedia('video/mp4; codecs="hev1"', 0) * 1.1,
checkMedia('video/ogg', 0),
checkMedia('video/webm; codecs="vp8"', 0),
checkMedia('video/webm; codecs="vp9"', 0)
@@ -58,7 +56,20 @@ const store = reactive({
{
name: '流媒体',
total: 0,
- scores: [1, 1, 0, 0],
+ scores: [
+ 1,
+ !!navigator.requestMediaKeySystemAccess ^ 0,
+ MediaSource.isTypeSupported(
+ 'video/mp4; codecs="avc1.42E01E, mp4a.40.2"'
+ )
+ ? 1.1
+ : 0,
+ MediaSource.isTypeSupported(
+ 'video/mp4; codecs="avc1.42E01E, mp4a.40.2"'
+ )
+ ? 1.1
+ : 0
+ ],
factor: 100,
items: [
'Media Source extensions',
@@ -67,30 +78,6 @@ const store = reactive({
'HTTP Live Streaming / HLS'
]
},
- {
- name: '自定义组件',
- total: 0,
- factor: 80,
- scores: [
- !!window.customElements ^ 0,
- !!document.body.attachShadow ^ 0,
- !!document.adoptedStyleSheets ^ 0
- ],
- items: ['Custom elements', 'Shadow DOM', 'adoptedStyleSheets']
- },
- {
- name: '图形图象支持',
- total: 0,
- factor: 120,
- scores: [
- checkCanvas('2d'),
- checkCanvas('webgl'),
- checkCanvas('webgl2'),
- checkCanvas('webgpu'),
- !!navigator.xr ^ 0
- ],
- items: ['canvas 2D', 'WebGL', 'WebGL 2', 'WebGPU', 'WebVR']
- },
{
name: '网络',
total: 0,
@@ -107,11 +94,106 @@ const store = reactive({
'fetch api',
'ArrayBuffer and Blob support'
]
+ },
+ {
+ name: '数据流',
+ factor: 80,
+ total: 0,
+ scores: [
+ !!window.FileSystemHandle ^ 0,
+ !!window.ReadableStream ^ 0,
+ !!window.WritableStream ^ 0
+ ],
+ items: ['File System', 'Readable Stream', 'Writable Stream']
+ },
+ {
+ name: '自定义组件',
+ total: 0,
+ factor: 80,
+ scores: [
+ !!window.customElements ^ 0,
+ !!document.body.attachShadow ^ 0,
+ document.adoptedStyleSheets ? 1.1 : 0
+ ],
+ items: ['Custom elements', 'Shadow DOM', 'adoptedStyleSheets']
+ },
+ {
+ name: '图形图象支持',
+ total: 0,
+ factor: 120,
+ scores: [
+ checkCanvas('2d'),
+ checkCanvas('webgl'),
+ checkCanvas('webgl2') * 1.1,
+ checkCanvas('webgpu') * 2,
+ navigator.xr ? 2 : 0
+ ],
+ items: ['canvas 2D', 'WebGL', 'WebGL 2', 'WebGPU', 'WebVR']
+ },
+ {
+ name: '点对点连接',
+ total: 0,
+ factor: 40,
+ scores: [
+ !!(
+ window.RTCPeerConnection ||
+ window.webkitRTCPeerConnection ||
+ window.mozRTCPeerConnection
+ ) ^ 0,
+ window.RTCIceTransport ||
+ window.webkitRTCIceTransport ||
+ window.mozRTCIceTransport
+ ? 2.5
+ : 0,
+ !!navigator.getUserMedia ^ 0,
+ navigator.mediaDevices && navigator.mediaDevices.getDisplayMedia
+ ? 1.5
+ : 0,
+ !!window.MediaRecorder ^ 0
+ ],
+ items: [
+ 'WebRTC 1.0',
+ 'ObjectRTC API for WebRTC',
+ 'Access the webcam',
+ 'Screen Capture',
+ 'Media Stream recorder'
+ ]
+ },
+ {
+ name: 'ES6模块',
+ total: 0,
+ factor: 40,
+ scores: [1, env.SUPPORT_ASSERTIONS ? 2.5 : 0],
+ items: ['import/export', 'Import assertions']
+ },
+ {
+ name: '性能',
+ total: 0,
+ factor: 70,
+ scores: [!!navigator.serviceWorker ^ 0, window.WebAssembly ? 1.5 : 0],
+ items: ['Web Workers', 'WebAssembly']
+ },
+ {
+ name: '其他',
+ total: 0,
+ factor: 80,
+ scores: [
+ !!navigator.bluetooth ^ 0,
+ navigator.clipboard ? 0.8 : 0,
+ navigator.usb ? 2 : 0,
+ !!navigator.windowControlsOverlay ^ 0
+ ],
+ items: ['Bluetooth', 'clipboard', 'USB', 'Window Controls Overlay']
}
]
})
-store.modules.forEach(it => (it.total = it.items.length))
+store.modules.forEach(
+ it => (
+ (it.total = it.items.length),
+ (it.passed = it.scores.filter(n => n > 0).length)
+ )
+)
store.scores = store.modules.map(it => it.scores.sum() * it.factor).sum()
export default function (app) {
diff --git a/src/views/main.vue b/src/views/main.vue
index 3af6954..c32e88a 100644
--- a/src/views/main.vue
+++ b/src/views/main.vue
@@ -4,7 +4,7 @@